链表程序出现Segmentation Fault错误,请求技术排查帮助
动态链表段错误问题分析与修复
我在实现动态链表时遇到了Segmentation Fault错误,GDB显示错误出在LIST_CL.H文件中l_print函数的node = node->next行。空链表(list_cl结构体的head和tail均为NULL)时无异常,但只要链表存在一个或多个节点就会触发错误。试过纸面调试没找到问题,附上插入和打印功能的完整代码:
完整代码
LIST.C
#include <stdio.h> #include <string.h> //for strcpy #include "cl_list.h" #include "list_cl.h" #define STRING_SIZE 25 int main(){ list_cl class = L_EMPTYLIST_CL; puts("Select command:"); puts("0. Exit."); puts("1. Insert node."); puts("6. Print all nodes in the linked list."); int k = 0; scanf("%d", &k); while(k != 0){ switch(k){ case 1: char cf[17] = ""; char first_name[STRING_SIZE] = ""; char last_name[STRING_SIZE] = ""; getchar(); puts("Insert name:"); fgets(first_name, sizeof(first_name), stdin); puts("Insert surname:"); fgets(last_name, sizeof(last_name), stdin); puts("Insert fiscal code:"); fgets(cf, sizeof(cf), stdin); client cliente; strcpy(cliente.cf, cf); cliente.first_name = first_name; cliente.last_name = last_name; class = l_add_cl(class, cliente); puts("Node inserted."); break; case 6: l_print(class); break; default: break; } scanf("%d", &k); } }
LIST_CL.H
list_cl l_add_cl(list_cl l, client p){ l_node node; node.id = 1; node.person = p; node.next = NULL; if(l.head == NULL){ //List is empty l.head = &node; l.tail = &node; } else { l.tail -> next = &node; l.tail = &node; } return l; } void l_print(list_cl l){ l_node *node = NULL; node = l.head; while(node != NULL){ //client *cliente = &node->person; //printf("ID Elemento: %d | Name: %s Surname: %s Fiscal Code: %s", node->id, cliente->first_name, cliente->last_name, cliente->cf); node = node->next; // SEGMENTATION FAULT ERROR HERE! } }
CL_LIST.H
#include "client.h" typedef struct _node { unsigned int id; client person; struct _node *next; } l_node; typedef struct { l_node *head; l_node *tail; } list_cl; #define L_EMPTYLIST_CL {NULL,NULL}
CLIENT.H
typedef struct { char cf[17]; char *first_name; char *last_name; } client;
问题根源
1. 栈内存节点失效导致野指针
l_add_cl函数中声明的l_node node是栈局部变量,函数执行完毕后,栈上的该节点内存会被系统回收。但你把&node赋值给链表的head、tail及前节点的next指针,这些指针直接变成野指针——指向已无效的内存区域。l_print访问这些指针时,自然触发段错误。
2. 字符串指针指向栈内存悬空
main函数中first_name和last_name是栈上的字符数组,你把它们的地址赋值给cliente.first_name和cliente.last_name,并拷贝到链表节点中。当case 1代码块执行完毕,这两个栈数组内存被回收,后续访问会出现未定义行为。
修复方案
1. 动态分配链表节点内存
修改l_add_cl函数,用malloc分配堆内存,确保函数结束后节点内存不被回收:
#include <stdlib.h> // 引入malloc所需头文件 list_cl l_add_cl(list_cl l, client p){ // 动态分配节点内存 l_node *node = malloc(sizeof(l_node)); if(node == NULL){ puts("内存分配失败"); return l; } node->id = 1; node->person = p; node->next = NULL; if(l.head == NULL){ l.head = node; l.tail = node; } else { l.tail->next = node; l.tail = node; } return l; }
2. 为字符串分配独立堆内存
修改main函数中client结构体的赋值逻辑,避免字符串指针指向栈内存:
case 1: char cf[17] = ""; char first_name[STRING_SIZE] = ""; char last_name[STRING_SIZE] = ""; getchar(); puts("Insert name:"); fgets(first_name, sizeof(first_name), stdin); // 去除fgets读取的换行符 first_name[strcspn(first_name, "\n")] = '\0'; puts("Insert surname:"); fgets(last_name, sizeof(last_name), stdin); last_name[strcspn(last_name, "\n")] = '\0'; puts("Insert fiscal code:"); fgets(cf, sizeof(cf), stdin); cf[strcspn(cf, "\n")] = '\0'; client cliente; strcpy(cliente.cf, cf); // 为名字分配堆内存并拷贝内容 cliente.first_name = malloc(strlen(first_name) + 1); if(cliente.first_name != NULL){ strcpy(cliente.first_name, first_name); } cliente.last_name = malloc(strlen(last_name) + 1); if(cliente.last_name != NULL){ strcpy(cliente.last_name, last_name); } class = l_add_cl(class, cliente); puts("Node inserted."); break;
3. 添加内存释放逻辑(可选但必要)
为避免内存泄漏,实现链表销毁函数释放所有资源:
void l_destroy_cl(list_cl l){ l_node *current = l.head; while(current != NULL){ l_node *next = current->next; // 释放字符串内存 free(current->person.first_name); free(current->person.last_name); // 释放节点内存 free(current); current = next; } }
在main函数退出前调用l_destroy_cl(class);即可。
内容的提问来源于stack exchange,提问作者Alessandro
相关产品推荐
相关产品推荐

