排查C语言指针练习脚本中的Segmentation Fault错误
Hey there! Let's break down the issues causing your segmentation fault and fix your code step by step.
Key Issues Leading to Segmentation Fault & Bugs
1. 野指针访问(Segmentation Fault的核心原因)
In your append_list function, you're creating struct IntItem addition as a local stack variable. When the function finishes executing, this stack memory gets reclaimed by the system. Any later attempts to access ls->head or ls->tail (which point to this now-invalid memory) result in a wild pointer dereference—this is exactly what's triggering your segmentation fault.
Fix: Use dynamic memory allocation (malloc) to create new nodes on the heap, so the memory persists after the function returns:
#include <stdio.h> #include <stdlib.h> // 引入malloc/free/exit所需头文件 #include <errno.h> // 用于perror输出错误信息 void append_list(struct IntList* ls, int item){ struct IntItem* addition = malloc(sizeof(struct IntItem)); if (!addition) { // 必须检查malloc是否分配成功! perror("Failed to allocate memory for new list item"); exit(EXIT_FAILURE); } addition->next = NULL; addition->value = item; if (!ls->head) { // 列表为空时,头和尾都指向新节点 ls->head = addition; ls->tail = addition; } else { ls->tail->next = addition; ls->tail = addition; } }
另外,记得在程序结束时释放链表内存,避免内存泄漏:
void free_int_list(struct IntList* ls) { struct IntItem* current = ls->head; while (current) { struct IntItem* temp = current; current = current->next; free(temp); } ls->head = NULL; ls->tail = NULL; }
在main函数末尾调用free_int_list(&ls);即可。
2. reduce函数中的多处问题
a. 未处理空列表情况
如果传入的列表为空,xs.head是NULL,执行struct IntItem current = *xs.head;会直接解引用空指针,引发崩溃。需要先添加前置检查:
b. 初始值设置错误与循环逻辑遗漏
- 你的
running初始值设为0,当使用max函数时,如果列表全是负数,结果会返回0而非列表中最大的负数。应该将running初始化为第一个元素的值。 - 循环条件
while (current.next)会跳过最后一个元素(因为最后一个节点的next是NULL),需要修改循环逻辑遍历所有非空节点。
c. 值传递的性能问题
将struct IntList按值传递会复制整个结构体,对于大列表会浪费内存,建议改为传递指针提升性能。
修复后的reduce函数:
int reduce(struct IntList* xs, int (*opy)(int, int)){ if (!xs->head) { return 0; // 如果需要空列表返回其他值,可以自行调整 } struct IntItem* current = xs->head->next; int running = xs->head->value; while (current) { running = opy(running, current->value); current = current->next; } return running; }
记得同步修改main中的调用代码,传递指针:
printf("Sum: %i\n", reduce(&ls, sum)); printf("Max: %i\n", reduce(&ls, max));
3. max函数的逻辑错误
你当前的max函数在x == y时会返回0(因为x>y和y>x都会被判定为0),替换为更简洁正确的实现:
int max(int x, int y){ return x > y ? x : y; }
完整修复后的代码
#include <stdio.h> #include <stdlib.h> #include <errno.h> struct IntItem { struct IntItem* next; int value; }; struct IntList { struct IntItem* head; struct IntItem* tail; }; void append_list(struct IntList* ls, int item){ struct IntItem* addition = malloc(sizeof(struct IntItem)); if (!addition) { perror("Failed to allocate memory for new list item"); exit(EXIT_FAILURE); } addition->next = NULL; addition->value = item; if (!ls->head) { ls->head = addition; ls->tail = addition; } else { ls->tail->next = addition; ls->tail = addition; } } void free_int_list(struct IntList* ls) { struct IntItem* current = ls->head; while (current) { struct IntItem* temp = current; current = current->next; free(temp); } ls->head = NULL; ls->tail = NULL; } int sum(int x, int y){ return x + y; } int max(int x, int y){ return x > y ? x : y; } int reduce(struct IntList* xs, int (*opy)(int, int)){ if (!xs->head) { return 0; } struct IntItem* current = xs->head->next; int running = xs->head->value; while (current) { running = opy(running, current->value); current = current->next; } return running; } int main(void) { struct IntList ls = {NULL, NULL}; printf("Start Script\n"); append_list(&ls, 1); append_list(&ls, 2); append_list(&ls, 3); printf("List Complete\n"); printf("Sum: %i\n", reduce(&ls, sum)); printf("Max: %i\n", reduce(&ls, max)); free_int_list(&ls); return 0; }
内容的提问来源于stack exchange,提问作者sgp667

