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
相关产品推荐
相关产品推荐

