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

C语言双向链表传入append函数时last指针未初始化问题

双向链表传参初始化值异常问题

问题描述

定义了带next和prev指针的双向链表结构体,计划从第一个链表提取卡路里为奇数的水果存入新建的第二个链表。运行时出现异常:第二个链表的first、last指针已经手动初始化为NULL,但传入append函数时,仅first指针保持NULL,last指针显示为未初始化状态。

复现代码

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <malloc.h>

typedef struct Node Node;
typedef struct DoubleList DoubleList;
typedef struct Fruit Fruit;

struct Fruit {
    char* name;
    int calories;
};

struct Node {
    Fruit info;
    Node* next, * prev;
};

struct DoubleList {
    Node* first;
    Node* last;
};

void append(DoubleList* list, Fruit f) {
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->info = f;
    new_node->next = NULL;
    new_node->prev = NULL;

    if (list->last) {
        list->last->next = new_node;
        new_node->prev = list->last;
        list->last = new_node;
    }
    else {
        list->last = list->first = new_node;
    }
}

int main() {
    DoubleList ld;
    ld.first = NULL;
    ld.last = NULL;

    append(&ld, createFruit("Avocado", 201));
    append(&ld, createFruit("Apple", 251));
    append(&ld, createFruit("Strawberries", 100));
    append(&ld, createFruit("Cherry", 50));

    DoubleList* ld2 = (DoubleList*)malloc(sizeof(DoubleList));
    ld2->first = NULL;
    ld2->last = NULL;
    Node* temp = ld.first;

    while (temp)
    {
        Node* aux = temp->next;
        if (temp->info.calories % 2 == 1) {
            // 错误写法:append(&ld2, temp->info);
            // 正确写法如下
            append(ld2, temp->info);
        }
        else {
            free(temp->info.name);
            free(temp);
        }
        temp = aux;
    }
    show(*ld2);
    return 0;
}

错误原因

核心错误为传参类型不匹配:

  • append形参要求传入DoubleList*类型(指向双向链表结构体的指针)。
  • 变量ld2本身就是DoubleList*类型,直接传入ld2即可匹配形参类型。
  • 错误写法append(&ld2, temp->info)传入的是ld2这个指针变量自身的地址,类型为DoubleList**,和形参类型完全不符。函数内部会把传入的地址当做DoubleList结构体的起始地址,按内存偏移读取first、last成员,实际访问的是不属于该结构体的野内存,因此会出现last值随机、未初始化的现象。

其他代码隐患

  • 原append函数插入尾节点时,没有给新节点的prev成员赋值为原尾节点,会导致双向链表的反向指针断裂。
  • 不要使用void main()写法,标准C中main返回值为int,函数末尾需加return 0;。
  • 节点转移时直接拷贝Fruit结构体,会导致新旧节点的name指针指向同一块堆内存。后续释放原链表偶数节点时,会把新节点name指向的内存一并释放,触发野指针访问。正确做法是给新节点的name单独分配内存,拷贝字符串内容,不要直接拷贝指针值。
  • 不要用new作为变量名,这是C++关键字,部分编译环境下会报错,建议替换为new_node这类名称。

调试截图

  • 进入append函数前:
    进入append函数前
  • 进入append函数后:
    进入append函数后

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:54:39