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

C语言超市管理项目商品数据写入txt文件乱码问题咨询

问题诱因
  • 文件写入逻辑错误(乱码直接原因):当前商品模块写入txt时,大概率直接通过fwrite写入了Produto结构体的整块内存。结构体除了需要持久化的ID、名称、价格、保质期、库存字段外,还包含next链表指针,该字段存储的是内存地址,每次程序运行地址随机,写入文本后就会出现你看到的大数字乱码;同时int、float类型的二进制值和文本编码不兼容,直接写内存块无法生成可读的文本内容。
  • 链表头指针更新失效:C语言指针是值传递,adicionarP函数接收的listaProduto是外部头指针的副本,函数内对listaProduto的赋值不会修改外部的真实头指针。第一次添加商品后外部头指针仍为NULL,后续遍历链表存文件时会访问非法内存,把内存里的随机残留值当成商品数据写入,进一步加剧内容错乱。
  • 隐藏逻辑bug:
    • fflush(stdin)属于C标准未定义行为,仅对输出流使用fflush是标准规定的合法操作,对输入流fflush在不同编译器下表现不一致,很容易读入输入缓冲区的脏数据。
    • 随机数种子srand放在ID生成函数内每次调用,1秒内多次调用时time()返回的时间戳相同,会生成重复ID。
    • ID生成范围为rand()%10,最多只能支持10个商品,超出后ID查重逻辑会死循环。
修复方案
  • 修复链表传参逻辑,将adicionarP的参数改为二级指针,保证头指针修改能同步到函数外部,同时替换非法的fflush(stdin):
void adicionarP(Produto** listaProduto) {
    Produto* novoProduto = (Produto*)calloc(1, sizeof(Produto));
    int auxInt = -1;
    float auxF = -1;
    
    printf("Digite o nome do produto: ");
    // 清空输入缓冲区残留内容,替代未定义的fflush(stdin)
    while(getchar() != '\n');
    fgets(novoProduto->nome, 10, stdin);
    novoProduto->nome[strcspn(novoProduto->nome, "\n")] = 0;
    
    novoProduto->ID= obterIdAleatorioP(*listaProduto);
    
    printf("Digite o preco do produto:");
    scanf("%f", &auxF);
    novoProduto->preco = auxF;

    auxInt = -1;
    printf("Digite a validade do produto:");
    scanf("%d", &auxInt);
    novoProduto->validade = auxInt;
    
    auxInt = -1;
    printf("Digite a Quantidade do stock:");
    scanf("%d", &auxInt);
    novoProduto->quantidade = auxInt;
    
    // 直接修改外部头指针
    *listaProduto = adicionarProduto(*listaProduto, novoProduto);
    printf("\nAdicionado com sucesso!\n");
}

调用该函数时传入头指针的地址即可,比如adicionarP(&头指针变量名)。

  • 重写文件读写逻辑,绝对不要直接写入结构体整块内存,按文本格式逐字段写入需要持久化的内容,跳过next指针字段:
// 保存商品列表到txt
void salvarProdutos(Produto* lista, const char* filePath) {
    FILE* fp = fopen(filePath, "w");
    if (!fp) {
        printf("Falha ao abrir arquivo!\n");
        return;
    }
    Produto* cur = lista;
    while (cur) {
        // 仅写入5个业务字段,不写入next指针
        fprintf(fp, "%d:%s:%.2f:%d:%d\n",
                cur->ID, cur->nome, cur->preco, cur->validade, cur->quantidade);
        cur = cur->next;
    }
    fclose(fp);
}

// 从txt加载商品列表
Produto* carregarProdutos(const char* filePath) {
    Produto* lista = NULL;
    FILE* fp = fopen(filePath, "r");
    if (!fp) return NULL;
    Produto temp;
    temp.next = NULL;
    // 按写入的格式逐字段读取
    while (fscanf(fp, "%d:%9[^:]:%f:%d:%d\n",
                  &temp.ID, temp.nome, &temp.preco, &temp.validade, &temp.quantidade) == 5) {
        Produto* novo = (Produto*)calloc(1, sizeof(Produto));
        *novo = temp;
        novo->next = NULL;
        lista = adicionarProduto(lista, novo);
    }
    fclose(fp);
    return lista;
}
  • 修复其他逻辑问题:
    • 把srand((unsigned) time(&t));移动到main函数最开头,整个程序只执行一次随机数种子初始化。
    • 扩大ID生成范围,比如将rand() % 10改为rand() % 10000,支持更多商品,避免数量上限过低导致死循环。
    • 代码中所有使用fflush(stdin)的位置,全部替换为while(getchar() != '\n');清空输入缓冲区。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 04:57:26