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

C语言二级指针作为函数参数的链表插入调用问题求助

问题排查与修正方案

嘿,我马上就发现了你代码里的核心问题,结合你说的长期用Java/C#的背景,其实就是C语言里指针传递和值传递的差异搞混了,还有链表头部插入的逻辑小疏漏,咱们一步步来改:

1. Push函数调用的传参错误

你的push函数定义是void push(rilevamenti_t ** head, ...),需要的是链表头指针的地址(也就是指针的指针),但你在main里调用的时候传的是lista1——这只是一个rilevamenti_t *类型的指针变量,相当于把指针的值传进去了,函数内部修改*head根本影响不到main里的lista1,结果就是链表永远建不起来,lista1一直是NULL。

修正方式:调用push时传入lista1的地址,也就是:

push(&lista1, tmpIdStazione, tmpNomeParametro, tmpCodiceParametro, tmpQuantita, tmpData);

2. 链表头部插入的逻辑缺失

你现在的push函数里只做了*head = new_rilevamento;,这会直接把新节点设为头,但原来的头节点会被彻底丢掉(还会造成内存泄漏)。正确的头部插入应该先让新节点的next指向原来的头,再把新节点更新为新的头:

修正后的push函数核心逻辑:

void push(rilevamenti_t ** head, char id[], char nome[], char codice[], float quant, char data[]) {
    rilevamenti_t * new_rilevamento = malloc(sizeof(rilevamenti_t));
    // 一定要检查malloc是否成功!C里不会自动处理内存分配失败
    if (new_rilevamento == NULL) {
        perror("Failed to allocate memory for new node");
        return;
    }

    // 填充结构体成员(补充完整你的省略逻辑)
    strncpy(new_rilevamento->idStazione, id, sizeof(new_rilevamento->idStazione)-1);
    // 手动添加字符串结束符,strncpy不会自动补全
    new_rilevamento->idStazione[sizeof(new_rilevamento->idStazione)-1] = '\0';
    strncpy(new_rilevamento->nomeParametro, nome, sizeof(new_rilevamento->nomeParametro)-1);
    new_rilevamento->nomeParametro[sizeof(new_rilevamento->nomeParametro)-1] = '\0';
    strncpy(new_rilevamento->codiceParametro, codice, sizeof(new_rilevamento->codiceParametro)-1);
    new_rilevamento->codiceParametro[sizeof(new_rilevamento->codiceParametro)-1] = '\0';
    new_rilevamento->quantita = quant;
    strncpy(new_rilevamento->data, data, sizeof(new_rilevamento->data)-1);
    new_rilevamento->data[sizeof(new_rilevamento->data)-1] = '\0';

    // 关键:先让新节点指向原头节点
    new_rilevamento->next = *head;
    // 再把新节点设为新的头
    *head = new_rilevamento;
}

3. 文件读取的逻辑优化

你原来用while(1)加feof的写法有坑——feof只有在读取到文件末尾之后才会返回真,也就是说当最后一次fscanf读取失败时,你还是会执行push,把临时变量里的无效数据插入链表。

修正后的读取循环:

// 直接用fscanf的返回值判断是否成功读取所有字段
while (fscanf(fp, "%s %s %s %f %s", 
              tmpIdStazione, tmpNomeParametro, tmpCodiceParametro, 
              &tmpQuantita, tmpData) == 5) {
    printf("Stazione: %s\n", tmpIdStazione );
    push(&lista1, tmpIdStazione, tmpNomeParametro, tmpCodiceParametro, tmpQuantita, tmpData);
}

这样只有当成功读取5个字段时才处理,彻底避免无效数据插入。

补充说明(帮你回忆C和Java/C#的差异)

Java/C#里的对象是引用传递,但C语言里只有值传递——如果你想在函数里修改一个变量(比如这里的链表头指针),必须把这个变量的地址传进去。rilevamenti_t **就是“指针的指针”,它让函数能直接操作main里的lista1变量,而不是操作它的副本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:40:36