向函数传递结构体指针时触发Segmentation Fault问题排查
问题根源:
insert_ll_string的循环逻辑完全写反了 你的段错误完全是因为insert_ll_string函数里遍历链表的循环条件搞反了,导致程序试图访问NULL指针的成员,触发了内存访问错误。
错误分析
先看你写的循环:
cur = dest; while (!cur->next) { cur = cur->next; } cur->next = item;
这个逻辑的问题在于:
!cur->next等价于cur->next == NULL,也就是说只有当当前节点已经是链表最后一个节点时,才会进入循环- 进入循环后,
cur = cur->next会把cur变成NULL(因为最后一个节点的next是NULL) - 接下来循环会再次判断
!cur->next,但此时cur已经是NULL,访问cur->next就是直接解引用空指针,这会触发段错误;就算侥幸没在循环里崩溃,循环结束后执行cur->next = item也是给NULL的成员赋值,同样会崩溃。
那为什么第一次调用insert_ll_string(ll_test1, ll_test2)没立即崩溃?这其实是未定义行为的“侥幸”——某些环境下,第一次解引用NULL可能没有立即触发崩溃,但已经埋下了隐患,第二次调用时就彻底爆发了。
修正后的insert_ll_string函数
正确的逻辑应该是遍历到链表的最后一个节点(也就是cur->next为NULL的节点),循环条件应该是当cur->next不为NULL时继续前进:
void insert_ll_string(struct ll_string *dest, struct ll_string *item) { struct ll_string *cur; if (!dest) { printf("dest can't be NULL\n"); return; } if (!item) { printf("item can't be NULL\n"); return; } cur = dest; // 遍历到最后一个节点(cur->next 为 NULL 的节点) while (cur->next != NULL) { cur = cur->next; } cur->next = item; }
这样循环会一直走到链表的最后一个有效节点,然后把item挂到它的next上,不会出现空指针访问的问题。
额外的潜在问题
除了这个导致崩溃的问题,你的代码还有几个需要修复的地方:
free_ll_string函数未释放最后一个节点
目前的free_ll_string只释放了链表中除最后一个节点外的所有节点,因为循环条件是next = ll_string->next不为NULL时才执行。修正方法是调整逻辑:void free_ll_string(struct ll_string *ll_string) { struct ll_string *next; while (ll_string != NULL) { next = ll_string->next; free(ll_string->string); free(ll_string); ll_string = next; } }- 测试代码中重复
strdup的冗余
你在测试函数里对字符串做了strdup,然后传给create_ll_string,而create_ll_string里又做了一次strdup——这会导致每个字符串有两份内存副本,虽然你最后都free了,但属于不必要的内存分配,可以直接把字面量传进去:
这样就不需要在测试函数里做ll_test1 = create_ll_string("test_string1", NULL); ll_test2 = create_ll_string("test_string2", NULL); ll_test3 = create_ll_string("test_string3", NULL);strdup和后续的free了。
内容的提问来源于stack exchange,提问作者kachink
相关产品推荐
相关产品推荐

