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

C语言实现链表pop操作在长度为1时触发段错误问题排查

C语言单链表pop函数长度为1时触发段错误问题

问题现象

使用C语言实现单链表相关功能时,append(尾插元素)、len(获取链表长度)、print_list(打印链表)函数均可正常运行,但pop(尾删元素)函数存在异常:链表长度大于1时pop执行正常,仅当链表长度为1时执行pop会触发Segmentation fault(段错误)。

复现场景

测试输入第一行指定操作总数为20,依次执行以下操作:

  • append 1
  • append 2
  • append 3
  • print(正常输出1 2 3)
  • pop
  • print(正常输出1 2)
  • pop
  • print(正常输出1)
  • 再次执行pop时终端返回Segmentation fault: 11错误。

已验证两种临时修改方式可让长度为1时的pop正常运行:

  1. 注释掉pop函数中处理长度大于2场景的逻辑块
  2. 在len()==1的处理分支(将PythonListHead置为NULL)后添加return语句

完整问题代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct Node
{
    int data;
    struct Node* next;
};

// create a node with data as x
struct Node* create_node(int x) {
    struct Node* ptr = malloc(sizeof(struct Node)); 
    ptr->next = NULL;
    ptr->data = x;
    return ptr;
}

// delete the node at `ptr` and free its memory
void delete_node(struct Node* ptr) {
    free(ptr);
}
struct Node* PythonListHead = NULL;


// prints the list in space-separated format
void print_list(struct Node* head) {
    struct Node* cur = head;
    while(cur) {
        printf("%d ", cur->data);
        cur = cur->next;
    }
    printf("\n");
}

// Add an item to the end of the list
void append(int x) {
    struct Node *cursor=PythonListHead;
    struct Node* a=create_node(x);
   if (PythonListHead==NULL){ 
       PythonListHead=create_node(x);
    }
   else{
       while(cursor->next!=NULL){
           cursor=cursor->next;
       }
       cursor->next=a;
   }
}
// Return the number of elements in the list
int len() {
    struct Node* last=PythonListHead;
    int count=0;
    while (last->next!=NULL){
        count++;
        last=last->next;
    }
    return count+1;
}


// Remove the item at the end of the list
void pop() {
    if (len()==1){
        PythonListHead=NULL;
    }
    if (len()==2){
        delete_node(PythonListHead->next);
        PythonListHead->next=NULL;
    }
    else{
        struct Node* cursor=PythonListHead;
        int count=0;
        while (cursor){
            cursor=cursor->next;
            count++;
            if (count==(len()-2)){
                delete_node(cursor->next);
                cursor->next=NULL;
            }
        }
    }
}
int main(int argc, char const *argv[])
{
    int T; 
    scanf("%d", &T);

    char operation_type[20];
    int indices[100];

    while(T--) {
        scanf("%s", operation_type);

        if(strcmp(operation_type, "append") == 0) {
            int x;
            scanf("%d", &x);
            append(x);
        } 

        if(strcmp(operation_type, "pop") == 0) {
            pop();
        }

        if(strcmp(operation_type, "len") == 0) {
            int length = len();
            printf("%d\n", length);
        }
        if(strcmp(operation_type, "print") == 0) {
            print_list(PythonListHead);
        }
    }
}

核心疑问

按照逻辑判断,当len()==1时本不应该进入后续处理长度为2、长度大于2的分支,为什么依然会触发段错误?

故障成因

段错误的直接原因是分支判断写法错误+空指针解引用,具体触发流程如下:

  1. pop函数使用了3个独立的if语句做分支判断,而非互斥的if-else if-else结构,也没有在匹配到分支后提前return终止函数,导致前一个分支修改链表状态后,后续判断逻辑会继续执行。
  2. 当链表长度为1进入pop逻辑时:
    • 首先进入第一个if (len()==1)分支,代码将全局头指针PythonListHead设置为NULL,但既没有释放原头节点的内存(存在内存泄漏),也没有退出函数。
    • 代码继续向下执行第二个if (len()==2)判断,此时会再次调用len()函数:len()函数中直接将局部指针last赋值为已经是NULL的PythonListHead,紧接着在while循环中执行last->next访问空指针的成员,直接触发段错误,根本走不到长度判断的步骤。

额外存在的代码问题

  • len()函数本身存在空指针风险:当链表为空(PythonListHead == NULL)时,直接访问last->next必然崩溃,正常实现需要先判断头指针是否为空,为空直接返回0。
  • append函数存在内存泄漏:无论链表是否为空,函数开头都会创建一次节点a,但链表为空时又调用了一次create_node(x)给头指针赋值,之前创建的a没有被释放也没有被使用,直接造成内存泄漏。
  • pop函数长度为1的分支没有释放原头节点内存,会造成内存泄漏。
  • pop函数遍历尾节点时反复调用len()遍历链表,时间复杂度为O(n²),可以通过一次遍历直接找到倒数第二个节点优化性能。

内容的提问来源于stack exchange,提问作者Tatai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 22:03:23