添加Note节点删除功能后,选择case3时触发segmentation fault (core dumped)报错
链表删除功能触发段错误的定位与修复方案
第一步:快速定位崩溃位置
- 带调试信息编译代码:
gcc -g your_code.c -o demo,关闭编译优化以匹配源码行号 - 用gdb运行程序复现case3的操作,段错误触发后输入
bt查看栈回溯,可直接定位到deleteNote函数内的无效内存访问行 - 也可通过valgrind做内存检查:
valgrind --tool=memcheck ./demo,工具会直接报出访问非法内存的具体代码位置、触发场景
核心崩溃根因
代码在删除逻辑里存在多处无效内存访问的漏洞,也是段错误的直接来源:
- 找匹配节点的内层循环退出时,没有区分退出原因:循环退出要么是找到了值为x的节点,要么是遍历完整条链表走到了
t == NULL的末尾。原代码没有判断t是否为NULL,直接执行prev->next = t->next,对NULL指针解引用,直接触发段错误——最常见的触发场景就是要删除的x值在链表中根本不存在。 prev变量未初始化,是栈上的随机野指针:当遍历过程中第一个碰到的节点就是匹配值x时,prev从未被赋值,后续对prev->next的写操作会直接往随机内存地址写入数据,触发崩溃。- 最开始判断链表为空的分支没有加
return,打印完提示后会继续执行后续遍历逻辑,逻辑上存在隐患。 - 外层循环的流程逻辑冗余,没有在链表遍历到末尾时及时退出循环,会持续触发无效访问。
修复后的可运行代码
void deleteNote(int x){ Note *t = head; Note *prev = NULL; // 初始化prev,避免野指针 // 链表为空时直接返回,不执行后续逻辑 if(head == NULL){ printf("List already empty.\n"); return; } // 先处理链表头部连续匹配的节点 while(t != NULL && t->data == x){ head = t->next; free(t); number--; // 维护全局节点计数 t = head; printf("Note %d deleted.\n", x); } // 头部节点全部删完后链表已空,直接返回 if(t == NULL){ return; } // 遍历剩余节点完成匹配删除 while(t != NULL){ if(t->data == x){ // 找到匹配节点,执行删除 prev->next = t->next; free(t); number--; t = prev->next; continue; } // 节点不匹配,同步移动prev和t指针 prev = t; t = t->next; } }
验证注意事项
- 覆盖所有边界测试场景:链表为空时触发删除、要删除的x值不存在、x值是链表最后一个节点、x值是链表头部连续多个节点,确保所有场景下不会触发非法内存访问
- 每次
free节点后,及时将遍历指针指向新的后继节点,避免使用已释放的野指针
内容的提问来源于stack exchange,提问作者adersat
相关产品推荐
相关产品推荐

