我目前有一个链表,需要添加用户从键盘输入的数据,所以我有两个结构:
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个节点的链接列表
答案 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)
我看到的问题:
您未将add->next
设为NULL
。
您正在本地更改data
。
add->next = data;
data = add;
在函数中本地更改data
的值。它不会更改调用函数中的值。
您有支票
while(data != NULL)
遵循if
声明
if(searchStudentID(data, add->StudentID)) {
但在searchStudentID(data, add->StudentID)
返回false
和data == NULL
开始时,我没有看到任何代码来添加新学生。