2015-04-02 86 views
0

我現在有一個鏈表,需要將數據添加到它是由鍵盤,使用戶輸入節點添加到鏈接列表我有兩個結構:使用功能

struct CourseInfo { 
    int courseID; 
    char courseName[30]; 
}; 
typedef struct CourseInfo courseinfo; 
struct StudentInfo { 
    char StudentID[10]; 
    char FirstName[21]; 
    char LastName[26]; 
    int num_course; 
    courseinfo array[10]; 
    struct StudentInfo *next; 
}; 

所以我目前有3個節點的鏈表。然後我需要調用一個函數並添加一個節點。節點需要被插入到正確的地方,這就是說,學生ID之前,它需要小於它和學生ID後需要更大,所以目前的ID我有111111111,3333333333和444444444和即時試圖添加222222222所以它會走在第二位,所以我的函數看起來像:

studentinfo *addStudent(studentinfo *data) //returns type studentinfo* now 
{ 
    studentinfo *add; 
    add = malloc(sizeof(studentinfo)); 
    add->next = NULL; //Now its set to NULL to begin 
    int knt; 
    printf("%s", "Adding new student:\nStudent ID: "); 
    scanf("%s", add->StudentID); 
    printf("%s", "First Name: "); 
    scanf("%s", add->FirstName); 
    printf("%s", "Last Name: "); 
    scanf("%s", add->LastName); 
    printf("%s", "Number of courses: "); 
    scanf("%d", &add->num_course); 
    for(knt = 0; knt < add->num_course; knt++) { 
     printf("%s", "Course ID: "); 
     scanf("%d", &add->array[knt].courseID); 
     printf("%s", "Course Name: "); 
     scanf("%s", add->array[knt].courseName); 
    } 
    if(searchStudentID(data, add->StudentID)) { 
     puts("immediately inside if"); 
     while(data != NULL) { 
      puts("Immediately inside while"); 
      if(strcmp(add->StudentID, data->StudentID) < 0) { 
       puts("inside if"); 
       add->next = data; 
       data = add; 
      } 
      else { 
       puts("inside first else"); 
       studentinfo *PrevPtr = data; 
       studentinfo *NPtr = data->next; 
       while(NPtr != NULL) { 
        ("inside while(NPTR != NULL)"); 
        if(strcmp(add->StudentID, NPtr->StudentID) < 0) { 
         add->next = PrevPtr; 
         PrevPtr->next = add; 
         break; 
        } 
        else { 
         puts("inside a differnet else"); 
         PrevPtr = NPtr; 
         NPtr = NPtr->next; 
        } 
       } 
       if(PrevPtr->next == NULL) { 
        puts("inside last if"); 
        add->next = NULL; 
        PrevPtr->next = add; 
       } 
      } 
     } 
    } 
    else { 
     puts("Found id"); 
    } 
    return data; //returns data back to call 
} 

,所以我說那些puts語句,因爲我想看看爲什麼程序保持崩潰。所以put語句puts("Inside a different else")卡住了一個無限循環並且保持打印。如果我們沒有ID,函數searchStudentID只返回1,如果我們已經有了它,則返回0。我知道這個功能可以工作,所以不需要發佈它。

我覺得問題可能在休息;語句,因爲它不退出第一while循環,但是從內環唯一的退出,但我不是陽性。調用該函數的樣子:

list = addStudent(list); //Now the new data is stored in list 

其中list是3個節點

+0

您是否使用調試器遍歷代碼 – pm100 2015-04-02 21:01:17

+0

@ pm100我目前使用的是code :: blocks,當我構建並運行時,我沒有遇到錯誤 – JackV 2015-04-02 21:02:42

+1

無關,else子句中的最後一條消息應爲:「Found id *和泄漏的內存*「關於實際問題,可以在任何地方說出來:'data =(anything)'意味着這個函數的調用者端沒有任何東西。 – WhozCraig 2015-04-02 21:07:11

回答

1

鏈接列表管理是關於管理節點指針,而不僅僅是節點。你想做幾件事情,讓自己更容易:

  • 將輸入步驟與搜索+插入步驟分開。無論他們看起來如何,他們都不屬於他們。這給你帶來的最大好處是將你的列表插入代碼減少到它應該做的事情(並且只有它應該做什麼):管理鏈接列表。我一直保持你的完整,但你應該真的是錯誤檢查,並在其他地方讀取數據。

  • 使用指向指針的指針來遍歷列表。這樣做的最大好處是不需要特殊的頭位插入。如果這是一個新節點最終會佔據的位置,那麼可以這樣做,但是消除這種特殊情況會進一步降低算法的複雜度。

  • 除非您能夠保留要用於插入邏輯的搜索結果,否則不要搜索列表。對鏈表執行O(N)掃描以確定輸入數據是否已經存在是沒有意義的,只有在再次搜索才能找到所述數據將被實際插入的位置。做一次。找到它所屬的位置。如果它已經在那裏,則什麼也不做,否則,你坐在正確的插入位置的懸崖上已經

  • 最後,除非你知道你需要一個新節點,否則不要分配一個新節點。使用一個自動變量,如果你最終什麼都不做,它會自動丟棄。

把所有的一起讓這樣的事情:

struct CourseInfo { 
    int courseID; 
    char courseName[30]; 
}; 
typedef struct CourseInfo CourseInfo; 

struct StudentInfo { 
    char StudentID[10]; 
    char FirstName[21]; 
    char LastName[26]; 
    int num_course; 
    CourseInfo array[10]; 
    struct StudentInfo *next; 
}; 
typedef struct StudentInfo StudentInfo; 

StudentInfo *addStudent(StudentInfo *head) 
{ 
    StudentInfo **pp = &head, *p = NULL, rec; 
    int knt; 

    // TODO: error check your inputs! 
    printf("%s", "Adding new student:\nStudent ID: "); 
    scanf("%s", rec.StudentID); 
    printf("%s", "First Name: "); 
    scanf("%s", rec.FirstName); 
    printf("%s", "Last Name: "); 
    scanf("%s", rec.LastName); 
    printf("%s", "Number of courses: "); 
    scanf("%d", &rec.num_course); 
    for(knt = 0; knt < rec.num_course; knt++) { 
     printf("%s", "Course ID: "); 
     scanf("%d", &rec.array[knt].courseID); 
     printf("%s", "Course Name: "); 
     scanf("%s", rec.array[knt].courseName); 
    } 

    // walk the list pointers, starting with head, looking for 
    // a node that is equal or greater than the input node 
    while (*pp && (knt = strcmp((*pp)->StudentID, rec.StudentID)) < 0) 
     pp = &(*pp)->next; 

    // leave now if already present 
    if (*pp && knt == 0) 
     return head; 

    // allocate new node 
    p = malloc(sizeof *p); 
    if (p == NULL) 
    { 
     perror("Failed to allocate new node"); 
     exit(EXIT_FAILURE); 
    } 

    // structure copy. 
    *p = rec; 

    // link into proper list position. 
    p->next = *pp; 
    *pp = p; 

    // always return the head (which may have updated above) 
    return head; 
} 

就是這樣。如前所述,我會親自執行除此功能之外的其他輸入操作,但我會將其留給您考慮。

祝你好運。

+0

非常感謝你非常詳細的答案,我有1,我不明白當你通過'p = malloc(sizeof * p)分配內存'不應該是'p = malloc(sizeof(studentinfo))'因爲不會'sizeof * p'爲0,因爲'* p = NULL ' – JackV 2015-04-02 22:59:32

+1

@JackRV'sizeof'是一個編譯時操作符構造;它的工作原理與你想象中的不同。 [看到這個問題和選擇的答案](http://stackoverflow.com/questions/19785518/is-dereferencing-null-pointer-valid-in-sizeof-operation) – WhozCraig 2015-04-02 23:01:22

+0

哦好吧,我明白感謝,作品不同於我認爲它會 – JackV 2015-04-02 23:07:27

0

鏈表由於此功能更新列表,您需要它是

studentinfo *addStudent(studentifo *data) 

並返回更新的頭值。或

void addStudent(studentifo **data) 

,做

*data = <new thing> 
0

的問題,我看到:

  1. 您沒有設置add->nextNULL

  2. 您在本地更改data

     add->next = data; 
         data = add; 
    

    在功能局部改變的data值。它不會更改調用函數中的值。

  3. 你必須檢查

    while(data != NULL) 
    

    if聲明

    if(searchStudentID(data, add->StudentID)) { 
    

    ,但我看不出有任何的代碼添加新的學生時searchStudentID(data, add->StudentID)回報falsedata == NULL下手。

+0

那麼如果searchStudentID返回0,那麼我不想添加數據,因爲學生已經在我們的文件 – JackV 2015-04-02 21:30:16

+0

@JackRV,這是有道理的。什麼情況下'數據== NULL'開始? – 2015-04-02 21:32:08

+0

所以我編輯我的問題和程序,以符合這個標準,我明白爲什麼我需要添加這些東西,雖然我的程序仍然陷在一個無限循環在同一地點 – JackV 2015-04-02 21:54:25