C语言链表测试触发Segmentation Fault,定位list_delete未找到问题
链表代码导致Segmentation Fault的原因及修复方案
1. list_size函数的do-while循环触发空指针访问
当链表为空时,*h为NULL,p = *h得到空指针。原代码的do-while循环会先执行一次循环体,直接访问空指针的next成员,触发段错误:
do { r += 1; p = p->next; // 此处访问空指针成员,直接崩溃 } while (p);
修复方案:将do-while改为while循环,先判断指针有效性再执行计数逻辑:
int list_size(const list_t *h) { node_t *p = *h; int r = 0; while (p) { r += 1; p = p->next; } return r; }
2. list_find函数缺少默认返回值
当遍历完链表未找到目标id的节点时,函数无明确return语句,C语言会返回栈上的随机值。若调用者误将该随机值当作有效指针使用,会触发未定义行为(包括段错误)。
修复方案:在函数末尾添加return NULL;,明确未找到时返回空指针:
node_t *list_find(const list_t *h, int id) { node_t *p = *h; while (p) { if (p->id == id) return p; p = p->next; } return NULL; // 未找到节点时返回NULL }
3. list_delete删除头节点的逻辑错误
原代码删除头节点时,直接将*h设为NULL,会导致链表中剩余节点全部丢失,同时不符合链表删除的正确逻辑:
// 原错误代码 if (*h && (*h)->id == id) { r = *h; *h = NULL; // 错误:未将链表头指向原头节点的下一个节点 return r; }
修复方案:将*h设为原头节点的next指针,保留剩余链表结构:
if (*h && (*h)->id == id) { r = *h; *h = (*h)->next; // 将链表头指向原头节点的下一个节点 r->next = NULL; // 可选:将被删除节点的next置空,避免野指针 return r; }
4. 测试代码中node_t成员未初始化(潜在问题)
如果linked_list.h中node_t的name和msg是字符指针类型(而非数组),test_delete_one中直接使用strcpy(n.name, "hello")会往未初始化的随机地址拷贝字符串,触发段错误。
修复方案:
- 若使用指针类型:先为
name和msg分配内存,使用完后释放:
void test_delete_one() { list_t h; list_init(&h); node_t n; n.id = 0; n.name = malloc(6); // 分配足够存储"hello"的内存(含结束符) n.msg = malloc(6); strcpy(n.name, "hello"); strcpy(n.msg, "world"); list_insert(&h, &n); node_t *f = list_delete(&h, 0); assert(f == &n); free(n.name); // 释放内存 free(n.msg); }
- 若使用数组类型:在
linked_list.h中定义固定大小的字符数组:
typedef struct node { int id; char name[20]; char msg[100]; struct node *next; } node_t; typedef node_t* list_t;
内容的提问来源于stack exchange,提问作者bloomsdayforever
相关产品推荐
相关产品推荐

