C语言操作.txt文件时输入信息保存为乱码的问题求助
问题:C语言操作TXT文件时写入内容出现乱码
控制台输入信息后,文件中保存的是奇怪字符,示例:
Q(@ `$@ 1 P ÿÿÿÿÿÿÿÿ1
附上原代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct Dados { char ID[2]; char NOME[50]; char EMAIL[50]; char TELEFONE[14]; char STATUS[1]; } Dados; Dados GetDados() { Dados dados; system("cls"); printf("\n\nDigite o ID: "); scanf("%s", dados.ID); printf("\n\nDigite seu primeiro nome: "); scanf("%s", dados.NOME); printf("\n\nDigite o Email: "); scanf("%s", dados.EMAIL); printf("\n\nDigite o Telefone: "); scanf("%s", dados.TELEFONE); rewind(stdin); return dados; } void ConsultarPorID(char ID[]) { FILE * arq; Dados dados; int encontrou = 0; if ((arq = fopen("c:\\pastadados\\newdados.txt", "r")) == NULL) { printf("Erro ao abrir o arquivo.\n"); return; } while (fscanf(arq, "%s%s%s%s", dados.ID, dados.NOME, dados.EMAIL, dados.TELEFONE) != EOF) { if (strcmp(dados.ID, ID) == 0) { printf("\n\tId: %s\n", dados.ID); printf("\tNome: %s\n", dados.NOME); printf("\tEmail: %s\n", dados.EMAIL); printf("\tTelefone: %s\n", dados.TELEFONE); encontrou = 1; } } if (!encontrou) { printf("Nenhum registro encontrado com o ID '%s'.\n", ID); } fclose(arq); } int main() { FILE * arq; Dados dados; char ID[2]; char NOME[50]; char EMAIL[50]; char TELEFONE[14]; char STATUS[1]; int resposta, idConsulta; printf("\n1 - Inserir dados\n\n2 - Consultar por ID\n\n3 - Consultar por nome\n\n4 - Consultar por email\n\n5 - Consultar por telefone\n\n6 - Excluir dados\n\n\nQue opcao deseja prosseguir? "); scanf("%d", &resposta); if(resposta == 1) { if ((arq = fopen("c:\\pastadados\\newdados.txt", "a")) == NULL) { printf("\n\nNao foi possivel criar o arquivo! :(\n\n"); exit(1); } else { do { GetDados(); fwrite(&dados, sizeof(Dados), 1, arq); printf("\n\nDados salvos com sucesso!\n"); printf("\nDeseja inserir mais dados? (s/n): "); resposta = getche(); } while (resposta != 'n' && resposta != 'N'); fclose(arq); } } else if (resposta == 2) { system("cls"); printf("Digite o ID que deseja consultar: "); scanf("%d", &idConsulta); fgets(ID, 2, stdin); ID[strcspn(ID, "\n")]; ConsultarPorID(ID); } else if (resposta == 6) { remove("c:\\pastadados\\newdados.txt"); printf("\nDados excluidos com sucesso!"); } return 0; }
错误原因分析
- 二进制写入与文本读取不兼容:使用
fwrite以二进制格式写入结构体,但查询时用fscanf按文本格式读取,两种方式的存储逻辑完全不同,必然导致乱码。 - 未接收结构体返回值:
GetDados()函数返回了填充好的结构体实例,但main函数中仅调用GetDados();,没有将返回值赋值给dados变量,导致写入文件的是未初始化的垃圾内存数据。 - ID处理逻辑错误:查询时将ID当作整数读取(
scanf("%d", &idConsulta)),但结构体中ID是字符数组,后续转换和传递完全错误,导致查询用的ID是无效值。 STATUS数组长度不足:char STATUS[1];无法容纳C语言字符串(字符串需要末尾的\0终止符),会造成内存越界,破坏其他字段的数据。getche()的问题:getche()是非标准库函数,兼容性差;且在scanf后调用会读取残留的换行符,导致循环判断异常。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct Dados { char ID[3]; // 增加长度,容纳ID和终止符 char NOME[50]; char EMAIL[50]; char TELEFONE[15]; // 增加长度,容纳号码和终止符 char STATUS[2]; // 至少2位存状态字符+终止符 } Dados; Dados GetDados() { Dados dados; system("cls"); // 限制输入长度,避免数组越界 printf("\n\nDigite o ID: "); scanf("%2s", dados.ID); printf("\n\nDigite seu primeiro nome: "); scanf("%49s", dados.NOME); printf("\n\nDigite o Email: "); scanf("%49s", dados.EMAIL); printf("\n\nDigite o Telefone: "); scanf("%14s", dados.TELEFONE); // 清理输入缓冲区的残留换行 while(getchar() != '\n'); return dados; } // 二进制方式读取查询 void ConsultarPorID(char ID[]) { FILE * arq; Dados dados; int encontrou = 0; if ((arq = fopen("c:\\pastadados\\newdados.txt", "rb")) == NULL) { printf("Erro ao abrir o arquivo.\n"); return; } // 用fread读取二进制结构体 while (fread(&dados, sizeof(Dados), 1, arq) == 1) { if (strcmp(dados.ID, ID) == 0) { printf("\n\tId: %s\n", dados.ID); printf("\tNome: %s\n", dados.NOME); printf("\tEmail: %s\n", dados.EMAIL); printf("\tTelefone: %s\n", dados.TELEFONE); encontrou = 1; break; // 找到后可退出循环 } } if (!encontrou) { printf("Nenhum registro encontrado com o ID '%s'.\n", ID); } fclose(arq); } int main() { FILE * arq; Dados dados; char ID[3]; int resposta; char confirm; printf("\n1 - Inserir dados\n\n2 - Consultar por ID\n\n3 - Consultar por nome\n\n4 - Consultar por email\n\n5 - Consultar por telefone\n\n6 - Excluir dados\n\n\nQue opcao deseja prosseguir? "); scanf("%d", &resposta); // 清理输入缓冲区 while(getchar() != '\n'); if(resposta == 1) { // 二进制追加写入 if ((arq = fopen("c:\\pastadados\\newdados.txt", "ab")) == NULL) { printf("\n\nNao foi possivel criar o arquivo! :(\n\n"); exit(1); } else { do { dados = GetDados(); // 接收返回的结构体 fwrite(&dados, sizeof(Dados), 1, arq); printf("\n\nDados salvos com sucesso!\n"); printf("\nDeseja inserir mais dados? (s/n): "); scanf("%c", &confirm); // 清理输入缓冲区 while(getchar() != '\n'); } while (confirm != 'n' && confirm != 'N'); fclose(arq); } } else if (resposta == 2) { system("cls"); printf("Digite o ID que deseja consultar: "); scanf("%2s", ID); ConsultarPorID(ID); } else if (resposta == 6) { if(remove("c:\\pastadados\\newdados.txt") == 0) printf("\nDados excluidos com sucesso!"); else printf("\nErro ao excluir dados!"); } return 0; }
关键修改说明
- 统一使用二进制读写:写入用
fwrite,读取用fread,文件打开模式对应ab和rb。 - 接收
GetDados()的返回值:将填充好的结构体赋值给dados,确保写入的是用户输入的数据。 - 修正数组长度:所有字符串数组预留足够空间存储
\0终止符,避免内存越界。 - 修复ID查询逻辑:直接按字符数组读取ID,避免类型转换错误。
- 替换
getche()为标准输入函数:用scanf读取确认字符,并清理输入缓冲区的残留换行,避免输入异常。 - 增加错误判断:删除文件时判断
remove的返回值,处理删除失败的情况。
内容的提问来源于stack exchange,提问作者zimmer
相关产品推荐
相关产品推荐

