C语言链表头部结构删除后打印异常,fgets调用后代码停滞
解决链表删除学生记录及fgets停滞的问题
兄弟,我看你在C语言链表操作和输入处理上卡壳了,这俩问题其实都是新手常踩的坑,我给你逐个捋清楚:
一、头部删除记录后打印出现异常文本
这个问题大概率是头部节点删除后没有正确更新head指针,导致后续遍历链表时访问了已经被释放的内存(也就是野指针),打印出来自然是乱码或者异常文本。另外如果有重复姓氏的节点,删除逻辑没处理好也可能出问题。
给你写个靠谱的按姓氏删除的函数,你可以参考:
#include <string.h> #include <stdlib.h> // 按姓氏删除所有匹配的学生记录 void delete_by_lastname(const char* target_lastname) { struct students *current = head; struct students *prev = NULL; // 先处理头部节点(可能多个匹配的头部) while (current != NULL && strcmp(current->lastname, target_lastname) == 0) { head = current->next; // 关键!更新head为下一个有效节点 free(current); // 释放当前节点内存 current = head; // 移动到新的头部继续检查 } // 处理非头部的匹配节点 while (current != NULL) { // 找到第一个匹配的节点 while (current != NULL && strcmp(current->lastname, target_lastname) != 0) { prev = current; current = current->next; } if (current == NULL) break; // 没有更多匹配,退出循环 // 删除当前节点 prev->next = current->next; free(current); current = prev->next; // 继续遍历后续节点 } }
这里的核心是:删除头部节点时必须更新head指针,不然原来的head指向的内存已经被释放,后续打印时访问这个野指针就会出现异常。另外要记得释放节点内存,避免内存泄漏。
打印链表的时候也要注意,必须从head开始遍历,直到current == NULL为止,别越界:
void print_students() { struct students *current = head; while (current != NULL) { printf("Name: %s %s, Score: %.2f, Zip: %d\n", current->firstname, current->lastname, current->score, current->zip); current = current->next; } }
二、调用fgets后代码停滞
这个问题几乎都是输入缓冲区残留的换行符搞的鬼!比如你之前用scanf读取score或者zip这类数值时,用户输入完按回车,scanf只会读取数值,而回车(\n)会留在输入缓冲区里。当你后续调用fgets时,它会直接读取这个换行符,导致看似“停滞”(其实是fgets已经读完了空行,可能你的逻辑没处理这种情况,就卡住了)。
解决方法很简单:在调用fgets之前,先清空输入缓冲区的残留字符:
// 安全清空输入缓冲区 void clear_input_buffer() { int c; while ((c = getchar()) != '\n' && c != EOF); }
然后在调用fgets前调用这个函数:
// 比如在add函数里读取名字前 clear_input_buffer(); printf("Enter first name: "); fgets(new_node->firstname, sizeof(new_node->firstname), stdin); // 别忘了去掉fgets读取到的换行符 size_t first_len = strlen(new_node->firstname); if (first_len > 0 && new_node->firstname[first_len - 1] == '\n') { new_node->firstname[first_len - 1] = '\0'; } // 读取姓氏同理 clear_input_buffer(); printf("Enter last name: "); fgets(new_node->lastname, sizeof(new_node->lastname), stdin); size_t last_len = strlen(new_node->lastname); if (last_len > 0 && new_node->lastname[last_len - 1] == '\n') { new_node->lastname[last_len - 1] = '\0'; }
另外要注意,fgets的第二个参数必须是数组的大小(比如sizeof(new_node->firstname)),这样能避免缓冲区溢出。
最后再提两个新手容易忘的点:
- 每次
malloc后一定要检查是否成功:if (new_node == NULL) { printf("Memory allocation failed!\n"); return; } - 程序结束前要遍历整个链表,释放所有节点的内存,避免内存泄漏
内容的提问来源于stack exchange,提问作者Hele
相关产品推荐
相关产品推荐

