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

C语言链表删除头节点Bug求助:删除后主指针值异常

C链表删除头节点后指针异常问题排查

我写了个简单链表,遇到个奇怪bug:先往头部加值1,再加值2,接着删除值为2的头节点。delete(head, 2)函数快返回时head->data == 1,但main里调用完这个函数后,head->data变成0了,输出结果完全不符合预期。

完整代码如下:

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

typedef struct linked_list
{
    int data;
    struct linked_list *next;
} linked_list_t;

void print_list(linked_list_t *head)
{
    linked_list_t *curr = head;
    printf("LIST: ");
    while (curr)
    {
        printf("%d ", curr->data);
        curr = curr->next;
    }
    printf("\n");
    fflush(stdout);
    
}

linked_list_t *add_to_front(linked_list_t *head, int data) 
{
    linked_list_t *new = malloc(sizeof(linked_list_t));
    if (!new) exit(1);
    new->next = head;
    new->data = data;
    return new;
}

void delete(linked_list_t *head, int data) 
{
    linked_list_t *current = head;
    linked_list_t *previous = NULL;
    // move current to the position of the node to delete
    while (current != NULL && current->data != data) 
    {
        previous = current;
        current = current->next;
    }

    if (current)
    {
        if (previous) 
        {
            // if the node to delete is not head
            previous->next = current->next;
        }
        else
        {
            // if the node to delete is head
            head = current->next;
        }
    }
    free(current);
}

int main()
{
    linked_list_t *head = NULL;
    print_list(head);
    // prints "LIST:"
    head = add_to_front(head, 1);
    head = add_to_front(head, 2);
    print_list(head);
    // prints "LIST: 2 1"
    // head->data = 1 just before delete() exits
    delete(head, 2);
    // head->data = 0 right after delete() exits
    print_list(head);
    // prints "LIST: 0 1" instead of "LIST: 1" 
}

问题根源

核心问题是delete函数里的head是值传递——你在函数内部修改head = current->next,只是修改了函数内部的局部变量,完全不会影响main函数里的head指针。当你删除头节点并free掉它之后,main里的head仍然指向这块已经被释放的内存,此时访问head->data属于访问野指针指向的已释放内存,值变成0是未定义行为的随机表现。

修复方案

有两种常用的修复方式:

方式1:让delete函数返回新的head指针

和你写的add_to_front逻辑保持一致,修改后返回新的头指针,在main里接收更新:

linked_list_t *delete(linked_list_t *head, int data) 
{
    linked_list_t *current = head;
    linked_list_t *previous = NULL;
    while (current != NULL && current->data != data) 
    {
        previous = current;
        current = current->next;
    }

    if (current)
    {
        if (previous) 
        {
            previous->next = current->next;
        }
        else
        {
            // 修改头节点时,更新局部head为新的头指针
            head = current->next;
        }
        free(current);
    }
    // 返回更新后的头指针
    return head;
}

main函数里调用时要更新head:

head = delete(head, 2);

方式2:使用二级指针直接修改原指针

通过传递指针的指针,直接在函数内部修改main里的head变量:

void delete(linked_list_t **head, int data) 
{
    linked_list_t *current = *head;
    linked_list_t *previous = NULL;
    while (current != NULL && current->data != data) 
    {
        previous = current;
        current = current->next;
    }

    if (current)
    {
        if (previous) 
        {
            previous->next = current->next;
        }
        else
        {
            // 通过二级指针修改原head指针
            *head = current->next;
        }
        free(current);
    }
}

main函数里调用时传入head的地址:

delete(&head, 2);

两种方式都能解决问题,第一种逻辑更贴合你现有代码的写法,第二种不需要返回值,直接修改原变量。另外要记住:访问已释放的内存是C语言中典型的未定义行为,结果可能随机变化,一定要避免这种情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 10:43:25