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

C语言结构体嵌套读文件报错:类型不兼容且数据仅存最后一行

问题解决:读取products.txt到recipe结构体的错误修复

问题背景

正在开发程序从stockroom.txt和products.txt读取数据并存储到指定结构体,结构体定义如下:

// 来自stockroom.txt的数据
struct ingredient {
    char* name;
    int number;
};
struct dose {
    int index;
    int amount;
};
// 来自products.txt的数据
struct recipe {
    char* name;
    int price;
    int number_ing;
    int current_price;
    int best_price;
    struct dose* ingredients;
};

实现read_recipes函数读取products.txt时出现两个问题:

  1. GCC报错:incompatible types when assigning to type 'struct dose' from type 'struct dose **'
  2. 调试发现仅保存最后一行配料数据

原read_recipes函数代码:

void read_recipes(int nr, int ni, struct recipe* recipes[], struct ingredient* ingredients[], FILE* products){
    int i, j, k;
    for (i = 0; i < nr; i++){
        char tmp_s[31];
        int tmp_n, n;
    
        fscanf(products, "%s %d %d", tmp_s, &tmp_n, &n);
        recipes[i] = (struct recipe *)malloc(sizeof(struct recipe));
        recipes[i] -> name = strdup(tmp_s);
        recipes[i] -> price = tmp_n;
        recipes[i] -> number_ing = n;
        recipes[i] -> current_price = 0;
        recipes[i] -> best_price = 0;
        recipes[i] -> ingredients = NULL;

        for(j = 0; j < n; j ++){
            char tmp_name[21];
            int tmp_amount;
            struct dose* doses[n];
            doses[j] = (struct dose*)malloc(sizeof(struct dose));
            fscanf(products, "%s %d", tmp_name, &tmp_amount);
            for(k = 0; k < ni; k++){
                if(strcmp(ingredients[k] -> name, tmp_name) == 0){
                    doses[j] -> index = k;
                    doses[j] -> amount = tmp_amount;
                }
            }
            recipes[i] -> ingredients = doses; // 错误位置
        }
    }
}

对应文件内容:

  • stockroom.txt:
6
flour 35
sugar 40
eggs 20
milk 25
cocoa 48
jam 10
  • products.txt:
3
Easter_eggs 6 2
cocoa 8
milk 3
Sacher_cake 22 3
flour 4
cocoa 14
jam 2
Mimosa_cake 13 5
eggs 3
flour 4
sugar 6
milk 4
jam 2

错误原因分析

  1. 类型不匹配:recipes[i]->ingredients的类型是struct dose*(用作连续结构体数组的指针),而doses是struct dose*[](指针数组,本质为struct dose**),直接赋值导致类型兼容报错。
  2. 内存管理错误:struct dose* doses[n];是j循环内的栈数组,每次循环都会重建,出循环后内存自动释放;且每次循环都覆盖赋值ingredients,最终仅保留最后一次循环的无效内存地址。
  3. 冗余内存分配:单个dose无需单独malloc,应为整个配料数组分配连续内存,直接操作数组元素即可。

修复后的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void read_recipes(int nr, int ni, struct recipe* recipes[], struct ingredient* ingredients[], FILE* products){
    int i, j, k;
    for (i = 0; i < nr; i++){
        char tmp_s[31];
        int tmp_n, n;
    
        fscanf(products, "%s %d %d", tmp_s, &tmp_n, &n);
        recipes[i] = malloc(sizeof(struct recipe));
        recipes[i]->name = strdup(tmp_s);
        recipes[i]->price = tmp_n;
        recipes[i]->number_ing = n;
        recipes[i]->current_price = 0;
        recipes[i]->best_price = 0;
        
        // 提前为当前食谱的配料数组分配连续内存
        recipes[i]->ingredients = malloc(n * sizeof(struct dose));
        if (recipes[i]->ingredients == NULL) {
            fprintf(stderr, "内存分配失败:无法为食谱配料分配空间\n");
            exit(EXIT_FAILURE);
        }

        for(j = 0; j < n; j++){
            char tmp_name[21];
            int tmp_amount;
            fscanf(products, "%s %d", tmp_name, &tmp_amount);
            
            // 查找对应配料的索引,找到后立即退出循环
            for(k = 0; k < ni; k++){
                if(strcmp(ingredients[k]->name, tmp_name) == 0){
                    recipes[i]->ingredients[j].index = k;
                    recipes[i]->ingredients[j].amount = tmp_amount;
                    break;
                }
            }
        }
    }
}

关键修改点

  • 提前分配配料数组内存:在进入配料循环前,根据n(配料数量)为recipes[i]->ingredients分配连续的struct dose数组内存,解决类型不匹配和内存失效问题。
  • 直接操作数组元素:移除栈上的doses数组,直接通过recipes[i]->ingredients[j]访问并赋值配料的index和amount,无需单独分配单个dose的内存。
  • 添加内存分配检查:增加malloc后的空指针校验,避免内存分配失败引发后续错误。
  • 优化查找逻辑:找到匹配配料后立即break,减少不必要的循环遍历。

验证说明

修复后,程序可正确读取products.txt中的所有配料数据,每个食谱的ingredients数组会完整保存对应数量的配料信息,不再出现类型错误和数据丢失问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 12:10:55