You need to enable JavaScript to run this app. C语言读取文件存入struct数组后,遍历输出仅显示最后一个条目的问题
优惠活动
大模型
产品
解决方案
定价
更多

C语言读取文件存入struct数组后,遍历输出仅显示最后一个条目的问题

核心问题定位

所有条目输出全为Frank的根本原因,是结构体中的字符串指针没有独立分配内存,全部指向了getline复用的同一块共享缓冲区。

问题底层逻辑拆解

  1. getline的工作机制:当传入的buf指针为NULL时会自动申请内存;当buf已经指向有效内存时,会直接在这块内存上扩容、覆盖写入新读取的行内容,全程复用同一块物理内存,不会为每次读取的内容申请独立空间。
  2. 循环中通过strsep切割得到的name_duplicate,本质是指向上述共享缓冲区内部的子串指针,并不是独立的内存块。每次给cards[i]->name赋值时,三个结构体的name字段最终全都指向了同一块被反复覆盖的buf内存。
  3. 循环结束后,buf中存储的是最后一次读取的Frank内容,三个结构体的name指针解引用时,自然全部读到Frank。

额外注意:如果输入内容是被双引号包裹的(比如"Bob"),当前的strsep切割逻辑会把第一个引号前的空串当成name赋值给结构体,需要多调用一次strsep跳过开头的引号,才能拿到真正的名字内容。


附带的逻辑风险
  • 变量未初始化问题:代码中cardsaccum、num_entries都是栈上的未初始化变量,初始值是随机垃圾值,第一次realloc计算的内存大小完全不可控,极易触发堆越界。
  • 内存泄漏风险:当前realloc的写法是直接将返回值赋值给原cards指针,如果分配失败会返回NULL,直接覆盖掉原来已经分配的数组地址,造成内存泄漏。
  • 内存释放逻辑缺陷:当前释放代码只free了每个card_t结构体本身、顶层cards数组和共享buf,没有对结构体内部的字符串指针做单独释放,后续如果为字符串字段分配独立内存,就会出现严重的内存泄漏。

修复方案
  1. 为字符串字段做独立内存拷贝
    不要直接将切割得到的子串指针赋值给结构体字段,改用strdup为每个字段申请独立内存、拷贝字符串内容:
    cards[cards_count]->name = strdup(name_duplicate);
    
    这一步彻底切断结构体字段和共享buf的关联,每个字段的值独立存储,不会被后续的getline操作覆盖。
  2. 修正计数变量的初始化与同步逻辑
    去掉冗余的重复计数变量,统一用一个计数变量管理数组长度,所有变量初始化为0:
    int cards_count = 0; // 统一记录已存储的卡片数量,避免多变量不同步
    card_t **cards = NULL;
    
  3. 修正realloc的安全写法
    用临时指针接收realloc的返回值,判空成功后再赋值给原指针,避免分配失败时丢失原有内存地址:
    card_t **tmp_cards = realloc(cards, sizeof(card_t *) * (cards_count + 1));
    if (tmp_cards == NULL) {
        // 内存分配失败时,先释放已分配的所有资源,再报错退出
    }
    cards = tmp_cards;
    
  4. 修正内存释放流程
    因为每个结构体内部的字符串字段都是独立分配的内存,释放时按层级顺序释放:
    // 先释放每个结构体内部的字符串字段
    for (int i = 0; i < cards_count; i++) {
        free(cards[i]->name);
        // 对cost、type、text、stats等其他字符串字段执行同样的free操作
        free(cards[i]); // 再释放结构体本身
    }
    free(cards); // 最后释放指针数组
    free(buf); // 释放getline使用的共享缓冲区
    fclose(input_file);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.02 00:06:05