使用函数将节点添加到链接列表

时间:2015-04-02 20:57:54

标签: c linked-list nodes

我目前有一个链表,需要添加用户从键盘输入的数据,所以我有两个结构:

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个节点的链表。然后我需要调用一个函数并添加一个节点。该节点需要插入正确的位置,即在它之前需要小于它的studentID和之后需要更大的studentID,所以我拥有的当前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语句,因为我想知道程序为什么会崩溃。所以puts语句puts("Inside a different else")陷入无限循环并继续打印。如果我们还没有ID,则函数searchStudentID只返回1,如果已经有ID,则返回0。我知道这个功能有效,所以不需要发布它。

我认为问题可能在于休息;声明,因为它不会从第一个while循环退出但只退出内部循环,但我不是正面。对此函数的调用如下所示:

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

其中list是具有3个节点的链接列表

3 个答案:

答案 0 :(得分: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;
}

那就是它。如上所述,我会亲自在除此功能之外的其他地方执行输入操作,但我留给您考虑。

祝你好运。

答案 1 :(得分:0)

由于此功能更新了列表,您需要它

studentinfo *addStudent(studentifo *data)

并返回更新的头部值。或

void addStudent(studentifo **data)

并做

*data = <new thing>

答案 2 :(得分:0)

我看到的问题:

  1. 您未将add->next设为NULL

  2. 您正在本地更改data

            add->next = data;
            data = add;
    

    在函数中本地更改data的值。它不会更改调用函数中的值。

  3. 您有支票

    while(data != NULL)
    

    遵循if声明

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

    但在searchStudentID(data, add->StudentID)返回falsedata == NULL开始时,我没有看到任何代码来添加新学生。