2015-04-02 90 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