You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

链表程序出现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 03:45:33