C语言单链表按birth_number删除节点功能异常问题咨询
问题排查与修复方案
原代码核心问题
- 参数传递错误:
node_delete函数传入head是值传递,函数内部修改head不会影响外部的链表头指针,导致头节点删除完全不生效。 - 遍历逻辑缺陷:循环判断条件为
temp->next != NULL,会跳过最后一个节点的匹配判断;且删除节点后直接访问已释放的temp->next属于野指针访问,会触发未定义行为。 - 指针维护错误:
previous指针未正确指向当前节点的前驱节点,删除非头节点时链表会直接断裂。 - 内存泄漏:删除节点时仅释放了
node_t结构体本身,未释放presenter和birth_number通过strdup申请的堆内存。 - 字符串操作风险:
scanf("%s", &birth_n)写法错误(数组名本身就是地址,不需要取址符);手动拼接换行符容易触发缓冲区溢出;调试版函数的字符串比较逻辑完全写反,匹配到目标反而不删除。 - 补充:原
node_load函数参数传入的file未被使用,内部硬编码读取DATABASE_FILE,属于潜在逻辑缺陷。
正确实现代码
方案1:返回新链表头(推荐,易使用)
#include <string.h> #include <stdlib.h> #include <stdio.h> node_t* node_delete(node_t *head) { char birth_n[14] = {0}; // 读入目标身份证号,限制长度避免溢出 scanf("%13s", birth_n); // 拼接换行符匹配fgets读入的格式,也可以选择在加载节点时提前去掉换行符 strncat(birth_n, "\n", 1); node_t *curr = head; node_t *prev = NULL; while (curr != NULL) { if (strcmp(birth_n, curr->birth_number) == 0) { node_t *to_free = curr; // 处理头节点删除 if (prev == NULL) { head = curr->next; } else { // 处理普通节点删除,衔接链表 prev->next = curr->next; } // 移动当前指针到下一个节点 curr = curr->next; // 释放节点内存 free(to_free->presenter); free(to_free->birth_number); free(to_free); } else { // 未匹配到,前驱和当前指针都后移 prev = curr; curr = curr->next; } } return head; }
调用方式示例
// 原链表头为head,删除后赋值回head即可 head = node_delete(head);
方案2:用二级指针传递头节点
void node_delete(node_t **head) { if (head == NULL || *head == NULL) return; char birth_n[14] = {0}; scanf("%13s", birth_n); strncat(birth_n, "\n", 1); node_t *curr = *head; node_t *prev = NULL; while (curr != NULL) { if (strcmp(birth_n, curr->birth_number) == 0) { node_t *to_free = curr; if (prev == NULL) { *head = curr->next; } else { prev->next = curr->next; } curr = curr->next; free(to_free->presenter); free(to_free->birth_number); free(to_free); } else { prev = curr; curr = curr->next; } } }
调用方式示例
// 传入头指针的地址 node_delete(&head);
可选优化建议
可以在加载节点时去掉字符串末尾的换行符,避免删除时需要额外拼接换行:
// 加载presenter时去掉换行 ptr->presenter = strdup(buffer); size_t len = strlen(ptr->presenter); if (len > 0 && ptr->presenter[len-1] == '\n') ptr->presenter[len-1] = '\0'; // birth_number同理处理 ptr->birth_number = strdup(buffer); len = strlen(ptr->birth_number); if (len > 0 && ptr->birth_number[len-1] == '\n') ptr->birth_number[len-1] = '\0';
处理后删除函数中不需要再拼接\n,直接比较输入的字符串即可。
内容的提问来源于stack exchange,提问作者Erri000
相关产品推荐
相关产品推荐

