2015-09-06 37 views
1

鑑於我在下面創建的結構,我將如何更改代碼以使其從insert(student)讀取,而不是現在的方式。基本上,目前的代碼需要輸入一個學生寫爲:在Struct中更改調用

student guy,23 

和輸出將是:

student guy (23) 

,這部分工作迄今。插入(和之前)代碼將執行的是多個學生輸入時,按字母順序對它們進行排序 - 或者如果它們具有相同的名稱,則按年齡排序。我已經完成了代碼,但似乎無法解決如何正確調用它。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h> 
#include <stdbool.h> 
#include <assert.h> 

#define MAX_LINE_LENGTH 80  // The longest line this program will accept 
#define MAX_NUM_STUDENTS 500 // The maximum number of students this program can handle 
#define MAX_NAME_SIZE 50  // The maximum allowable name length 

// The declaration of the student record (or struct). Note that 
// the struct contains the name as an array of characters, rather than 
// containing just a pointer to the name as before. 

typedef struct student_s Student; 

struct student_s { 
    char name[MAX_NAME_SIZE]; 
    int age; 
    Student* next;    // Pointer to next student in a list 
}; 

bool comesBefore(const Student* student1, const Student* student2) { 
    int name_compare = strcmp(student1->name, student2->name); 

    if (name_compare < 0) { 
     return true; 
    } 
    else if (name_compare == 0) { 
     int age1 = student1->age; 
     int age2 = student2->age; 
     if (age1 < age2) { 
      return true; 
     } 
    } 
    return false; 
} 

Student* insert(Student* student, Student* list) { 
    Student* curr = NULL; 
    Student* prev = NULL; 
    if (list == NULL) 
     return student; 

    if (comesBefore(student, list)) { 
     student->next = list; 
     return student; 
    } 

    for (curr = list, prev = NULL; 
     curr != NULL && comesBefore(student, curr) != true; 
     prev = curr, curr = curr->next); 

    assert(prev != NULL); 

    student->next = curr; 
    prev->next = student; 
    return list; 
} 


// Create a pool of student records to be allocated on demand 

Student studentPool[MAX_NUM_STUDENTS]; // The student pool 
int firstFree = 0; 
// Return a pointer to a new student record from the pool, after 
// filling in the provided name and age fields. Returns NULL if 
// the student pool is exhausted. 
Student* newStudent(const char* name, int age) { 
    Student* student = NULL; 
    if (firstFree < MAX_NUM_STUDENTS) { 
     student = &studentPool[firstFree]; 
     firstFree += 1; 
     strncpy(student->name, name, MAX_NAME_SIZE); 
     student->name[MAX_NAME_SIZE - 1] = '\0'; // Make sure it's terminated 
     student->age = age; 
     student->next = NULL; 
    } 
    return student; 
} 

// Read a single student from a csv input file with student name in first column, 
// and student age in second. 
// Returns: A pointer to a Student record, or NULL if EOF or an invalid 
// student record is read. Blank lines, or lines in which the name is 
// longer than the provided name buffer, or there is no comma in the line 
// are considered invalid. 
Student* readOneStudent(FILE* file) 
{ 
    char buffer[MAX_LINE_LENGTH]; // Buffer into which we read a line from stdin 
    Student* student = NULL;  // Pointer to a student record from the pool 

    // Read a line, extract name and age 

    char* cp = fgets(buffer, MAX_LINE_LENGTH, file); 
    if (cp != NULL) {   // Proceed only if we read something 
     char* commaPos = strchr(buffer, ','); 
     if (commaPos != NULL && commaPos > buffer) { 
      int age = atoi(commaPos + 1); 
      *commaPos = '\0'; // null-terminate the name 
      student = newStudent(buffer, age); 
     } 
    } 
    return student; 
} 

// Reads a list of students from a given file. Input stops when 
// a blank line is read, or an EOF occurs, or an illegal input 
// line is encountered. 
// Returns a pointer to the first student in the list or NULL if no 
// valid student records could be read. 
Student* readStudents(FILE *file) 
{ 
    Student* first = NULL;  // Pointer to the first student in the list 
    Student* last = NULL;  // Pointer to the last student in the list 
    Student* student = readOneStudent(file); 
    while (student != NULL) { 
     if (first == NULL) { 
      first = last = student; // Empty list case 
     } 
     else { 
      last->next = student; 
      last = student; 
     } 
     student= readOneStudent(file); 
    } 
    return first; 
} 


// printOneStudent: prints a single student, passed by value 
void printOneStudent(Student student) 
{ 
    printf("%s (%d)\n", student.name, student.age); 
} 


// printStudents: print all students in a list of students, passed 
// by reference 
void printStudents(const Student* student) 
{ 
    while (student != NULL) { 
     printOneStudent(*student); 
     student = student->next; 
    } 
} 

// Main program. Read a linked list of students from a csv file, then display 
// the contents of that list. 
int main(void) 
{ 
    FILE* inputFile = stdin; 
    if (inputFile == NULL) { 
     fprintf(stderr, "File not found\n"); 
    } 
    else { 
     Student* studentList = readStudents(inputFile); 
     printStudents(studentList); 

     // The program could now do various things that make use of 
     // the linked list, like deleting students and adding new ones, 
     // but the program is already quite long enough! 
    } 
} 

我相信它需要某種編輯以readStudents但不能工作了什麼叫轉變,使無論來源材料我已閱讀。

+0

目前,'readStudents'將每個新學生放在列表的最後。你需要刪除那部分代碼,而不是調用'insert'。 – kaylum

回答

2

的核心思想是,你需要調整此:

if (first == NULL) { 
     first = last = student; // Empty list case 
    } 
    else { 
     last->next = student; 
     last = student; 
    } 

目前你把新的學生在列表的末尾。相反,你要保持排序順序。在概念上你有

Arthur -> Bill -> Dave 

和一個新的記錄,查爾斯。所以你先與查爾斯比較,發現查爾斯更大,所以繼續比爾,然後最終擊中戴夫,現在知道在比爾之後和戴夫之前插入查爾斯。

現在看看insert()函數。你能看到這是它在做什麼嗎?走上榜單並最終插入唱片 - 注意它如何調整「Bill」以指向新唱片,並將新唱片指向Dave。