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

C语言链表函数行为差异疑问:delEven与delAll2为何效果不同?

C语言链表删除函数的指针操作差异问题

我在练习C语言链表时遇到一个疑问:创建存储1-10的链表后,delEven()函数通过P = *node操作能正常删除偶数元素,但用同样方式写的delAll2()却无法清空链表;而直接操作*node的delAll()功能正常。想搞清楚这两个函数行为不同的原因。

测试代码

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int dat;
    struct node* next;
};

void printList (struct node* node)
{
    if (node == NULL)
    {
        printf("empty\n");
        return;
    }
    while (node->next!=NULL)
    {
        printf("%2d",node->dat);
        node = node->next;
    }
    printf("%2d\n",node->dat);
}
void delEven(struct node** node)    
{
    struct node* P;
    P = *node;
    while (P->next != NULL)
    {
        if (P->next->dat%2==0)
        {
            P->next = P->next->next;
        }
        if(P->next->dat%2==0)
        {
            P->next = P->next->next;
        }
        P=P->next;
    }
}

void delAll(struct node** node)
{
    struct node* P;
    P = *node;
    while ((*node)->next != NULL)
    {
        *node = (*node)->next;
    }
    *node = (*node)->next;
}
void delAll2(struct node** node)
{
    struct node* P;
    P = *node;
    while (P != NULL)
    {
        P = P->next;
    }
}
void main()
{
    int i;
    struct node* start;
    struct node* Q;
    struct node* P;
    
    start = NULL;
    for(i=1; i<=10;i++)
    {
        Q=malloc(sizeof(struct node));
        Q->dat = i;
        Q->next = start;
        start = Q;
    }
    printList(start);
    printList(start);
    delEven(&start);
    printList(start);
    delAll2(&start);
    printList(start);
}

输出结果

使用delAll2()时的输出

10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
10 9 7 5 3 1
10 9 7 5 3 1

使用delAll()时的输出

10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
10 9 7 5 3 1
empty

原因解析

1. delEven()能生效的本质

delEven()中,P = *node让局部指针P指向原链表的头节点,后续操作的是P->next——也就是修改链表节点自身的next成员。这些节点属于原链表的一部分,修改它们的next指针会直接改变原链表的结构关系,所以删除操作的结果能被外部的start指针感知到。

2. delAll2()无效的核心问题

delAll2()里只是让局部指针P不断向后移动(P = P->next),直到P变为NULL。这个操作仅改变了局部变量P的指向,既没有修改原链表的任何节点,也没有改动*node(即外部的start指针)的值。外部的start仍然指向原来的头节点,自然链表没有任何变化。

3. delAll()生效的原因

delAll()直接操作*node(也就是外部start指针的地址),不断将*node的指向往后移动,最后把*node置为NULL。这相当于直接修改了外部的start指针,让它指向空地址,所以外部打印时显示链表为空。

额外提示

  • delAll()存在内存泄漏:它仅将start置为NULL,但未释放链表节点占用的内存,正确的清空逻辑应该逐个调用free()释放每个节点。
  • delEven()存在功能缺陷:如果头节点本身是偶数,不会被删除;连续偶数的处理逻辑也有漏洞(比如两个偶数连续时,第二个可能跳过判断)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 08:23:55