C语言fscanf读取固定宽度含空格记录返回乱码是什么原因?
C语言fscanf读取固定宽度带空格记录异常解决方案
根因分析
你遇到的乱码问题由以下多个错误共同导致:
- 格式串规则误用:
%30[^\n]、%20[^\n]的[^\n]匹配逻辑是读到换行符才停止,不会按照你指定的宽度截断,第一个匹配项会把姓名之后的所有字段内容全部读入,导致后续所有字段读取错位,内存溢出产生乱码。 - 字符串数组未预留结束符位置:比如
acct_no数组长度仅为8,用%8s读取时会写入8个字符+1个字符串结束符\0,直接越界访问破坏内存结构。 - 日期字段读写格式不匹配:写文件时用
%d%d%d输出日、月、年三个整数,最终生成连续的数字串(如27111960),读文件时用%d%d%d会将整个连续数字识别为第一个整数,后两个日期字段读取完全错位。 %c未跳过前置空白:%c默认不会跳过空格、制表符等空白字符,前面字段的补位空格会被识别为账户类型的值,导致后续字段进一步错位。- 文件指针位置错误:
a+模式打开文件时,默认指针指向文件末尾,直接调用fscanf读取不到任何有效内容,结构体变量未被赋值,输出随机内存值。 - 代码低级错误:
tmp变量未定义、free(pw_t)的pw_t变量不存在、Windows路径中的\未转义为\\,会导致路径识别错误。
修复方案
1. 调整宏定义与结构体
// 路径转义符修正 #define PATH "F:\\c\\projects\\Banking Management System\\data\\" #define F_ACCT "accounts.txt" #define FILENAME(file) PATH file // 写格式:日期固定宽度输出,%c前加空格跳过空白 #define F_ACCT_FPRINTF "%05d%-8s%-30s%02d%02d%04d%-20s%-20s%-20s %c%-15.2lf\n" // 读格式:固定宽度用%c读取,日期按固定宽度拆分 #define F_ACCT_FSCANF "%05d%8c%30c%2d%2d%4d%20c%20c%20c %c%lf\n" // 字符串数组长度+1,预留结束符位置 typedef struct Date { int dd; int mm; int ccyy; } Date; typedef struct Account { int id; char acct_no[9]; char name[31]; Date birthday; char telephone_no[21]; char mobile_no[21]; char tfn[21]; char acct_type; double acct_bal; } Account;
2. 读取后手动处理字符串
读完每个%c读取的字符串后,手动去掉尾部补位空格,添加结束符:
// 工具函数:去掉字符串尾部空格并补结束符 void trim_tail_space(char *str, int len) { int i = len -1; while(i >=0 && str[i] == ' ') i--; str[i+1] = '\0'; }
3. 修正主逻辑
int main(int argc, char *argv[]) { Account *ac_t=malloc(sizeof(Account)); if (ac_t==NULL) { perror("Fatal error: "); exit(EXIT_FAILURE); } FILE *fp=fopen(FILENAME(F_ACCT),"a+"); if (!fp) { free(ac_t); perror("ERROR:"); exit(EXIT_FAILURE); } // 移动文件指针到开头 fseek(fp, 0, SEEK_SET); int tmp = fscanf(fp,F_ACCT_FSCANF, &ac_t->id, ac_t->acct_no, ac_t->name, &ac_t->birthday.dd, &ac_t->birthday.mm, &ac_t->birthday.ccyy, ac_t->telephone_no, ac_t->mobile_no, ac_t->tfn, &ac_t->acct_type, &ac_t->acct_bal); // 处理字符串尾部空格 trim_tail_space(ac_t->acct_no, 8); trim_tail_space(ac_t->name, 30); trim_tail_space(ac_t->telephone_no, 20); trim_tail_space(ac_t->mobile_no, 20); trim_tail_space(ac_t->tfn, 20); // 输出调试 printf("\ntmp=%d", tmp); printf("\n[%d]",ac_t->id); printf("\n[%s]",ac_t->acct_no); printf("\n[%s]",ac_t->name); printf("\n[%d]",ac_t->birthday.dd); printf("\n[%d]",ac_t->birthday.mm); printf("\n[%d]",ac_t->birthday.ccyy); printf("\n[%s]",ac_t->telephone_no); printf("\n[%s]",ac_t->mobile_no); printf("\n[%s]",ac_t->tfn); printf("\n[%c]",ac_t->acct_type); printf("\n[%lf]",ac_t->acct_bal); system("pause"); free(ac_t); fclose(fp); return 0; }
内容的提问来源于stack exchange,提问作者Anil
相关产品推荐
相关产品推荐

