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

C语言union类型双向链表节点值全重复问题求解

问题原因

你的链表所有节点值重复是多个逻辑错误共同导致的:

  • 核心错误:节点存储值时直接复用了同一块内存地址。你定义的values是全局唯一的union数组,三次调用插入函数时传的都是这个数组的首地址,而插入函数里没有做值拷贝,直接把外部传入的地址存在节点里。后续每次输入新值都是在覆盖这块公共内存的内容,最终所有节点读到的都是最后一次写入的值。
  • 笔误:插入函数定义的名字是push_none,主函数里调用的名字是push_node,代码无法正常编译。
  • 存储逻辑和union特性不匹配:union同一时间只能保存一个成员的值,你每轮循环连续给union的不同成员赋值3次,前面写的值会被后面的覆盖;且你插入节点时只传了数组首地址,根本拿不到同轮输入的另外2个值。
  • 遍历错误:输出时直接移动链表的head指针,遍历结束后原链表的头节点地址丢失,会造成内存泄漏。
  • 多余的指针开销:节点里定义的是union指针,多了一层不必要的内存寻址,还容易出现野指针问题。
修复方案
  • 调整节点结构体,直接存储union值(不需要指针),如果需要一个节点存多个不同类型的值,额外给每个值加类型标记,避免读值时类型不匹配。如果需求是每个节点只存1个值,直接把插入逻辑移到值读取的循环内,每读入一个值就插入一次即可。
  • 统一插入函数名,插入节点时做值拷贝,不要直接存储外部传入的指针地址,保证每个节点的值存在独立的内存空间。
  • 遍历链表时用临时游标指针移动,不要修改链表原有的head、tail指针。
  • 程序结束前手动释放所有申请的堆内存(包括节点、strdup生成的字符串、链表本体),避免内存泄漏。
修正后可运行代码(按每个节点存3个带类型标记的值的逻辑实现)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 带类型标记的单个值结构
typedef struct {
    int type; // 1:int 2:double 3:string
    union {
        int as_int;
        double as_double;
        char *as_str;
    } val;
} typed_val;

struct list_t{
    struct node_t *head;
    struct node_t *tail;
};
struct node_t {
    typed_val vals[3]; // 每个节点存3个带类型的值,直接存值不存指针
    struct node_t *prev;
    struct node_t *next;
};

// 统一函数名
int push_node(struct list_t *list, typed_val* value);

int push_node(struct list_t *list, typed_val* value){
    if(list==NULL || value==NULL)return 1;
    struct node_t *node = (struct node_t*) malloc(sizeof(struct node_t));
    if(node==NULL)return 2;
    // 做值拷贝,每个节点存独立的副本,不依赖外部内存
    memcpy(node->vals, value, sizeof(typed_val)*3);

    if(list->head==NULL){
        node->next=NULL;
        node->prev=NULL;
        list->head = node;
        list->tail=node;
    } else{
        node->next=NULL;
        node->prev = list->tail;
        list->tail->next = node;
        list->tail = node;
    }
    return 0;
}

int main() {
    struct list_t * list = malloc(sizeof(struct list_t));
    list->tail=NULL;
    list->head=NULL;

    printf("Create a double linked list of 3 element :");
    char buf[100],**ptr=NULL;
    typed_val values[3]; // 每轮临时存3个值,插入时做拷贝
    int i=0;
    // 数据输入
    while (i<3){
        int j=0;
        while(j<3){
            while(1){
                printf("\n1 - INT\n2 -DOUBLE\n3 - CHAR\nEnter type:");
                scanf("%d", &values[j].type);
                if(values[j].type>0 && values[j].type<4)break;
            }
            printf("\nEnter value :");
            scanf("%s",buf);

            if(values[j].type==1){
                values[j].val.as_int = (int)strtol(buf,ptr,10);
            }
            else if(values[j].type==2){
                values[j].val.as_double = strtod(buf,ptr);
            }
            else if(values[j].type==3){
                values[j].val.as_str = strdup(buf);
            }
            j++;
        }
        // 插入时传入临时数组地址,函数内会做拷贝,后续覆盖values不影响已插入节点
        push_node(list,values);
        i++;
    }
    i=0;
    // 用临时指针遍历,不修改原head
    struct node_t *cur = list->head;
    while(cur!=NULL){
        int j=0;
        while(j<3){
            if(cur->vals[j].type==1){
                printf("%d ",cur->vals[j].val.as_int);
            }
            if(cur->vals[j].type==2){
                printf("%lf ",cur->vals[j].val.as_double);
            }
            if(cur->vals[j].type==3){
                printf("%s ",cur->vals[j].val.as_str);
            }
            j++;
        }
        printf("\n");
        i++;
        cur = cur->next;
    }

    // 内存释放逻辑可自行补充:遍历所有节点,先释放节点内strdup生成的字符串,再释放节点本身,最后释放list本体
    return 0;
}

如果你实际需求是每个节点只存1个值,只需要把节点里的typed_val vals[3]改成单个typed_val val,把push_node调用移到j循环内部,每读一个值就插入一次即可,逻辑更简单。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:57:11