C语言ReadPersonData函数读取输入文件数据异常求助
问题:读取结构体数组时爱好部分异常,程序提前终止
问题现象
读取输入文件时,当遇到爱好数量与实际爱好个数不匹配的条目(如示例中Sarah的条目:标注爱好数量为2,但实际跟随4个爱好),程序会停止读取后续所有数据。输入文件每条数据格式为:姓名、国家、城市、街道、爱好数量、爱好列表,示例数据片段如下:
John Brazil Brasilia Esplanada 1 Reading Mary Japan Tokyo Harajuku 2 Painting Swimming David Australia Canberra Northbourne 3 Running Gardening Cycling Sarah Norway Oslo Storgata 2 Cooking Fishing Writing Dancing
问题代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_NAME_LEN 32 #define MIN_HOBBIES 0 #define MAX_HOBBIES 10 #define MAX_PERSONS 100 #define MAX_FILE_NAME_SIZE 16 #define ARG_CNT 2 #define ARG_EXEC_NAME argv[0] #define ARG_FILE_NAME argv[1] typedef struct { char country[MAX_NAME_LEN]; char city[MAX_NAME_LEN]; char street[MAX_NAME_LEN]; } address; typedef struct { char name[MAX_NAME_LEN]; address residence; int hobbyCount; char hobbies[MAX_HOBBIES][MAX_NAME_LEN]; } person; int ReadPersonData(person personList[] , int limit, char *fName); void FindSameHobby(person personList[], int personCount, char hobbyName[]); void OutPutData(person personList[], int personCount, char hobbyName[]); int main(int argc, char **argv) { if(argc != ARG_CNT) { fprintf(stderr, "Usage: %s input_file\n", ARG_EXEC_NAME); return EXIT_FAILURE; } person personList[MAX_PERSONS]; int personCount = ReadPersonData(personList, MAX_PERSONS, ARG_FILE_NAME); return 0; } int ReadPersonData(person personList[] , int limit, char *fName) { int persons = 0; int i; FILE *fPerson = fopen(fName, "r"); if(fPerson == NULL) { fprintf(stderr, "Error opening input file %s", fName); perror(" "); return persons; } while(fscanf(fPerson, "%s %s %s %s %d", personList[persons].name, personList[persons].residence.country, personList[persons].residence.city, personList[persons].residence.street, &personList[persons].hobbyCount) == 5) { if(personList[persons].hobbyCount < MIN_HOBBIES || personList[persons].hobbyCount > MAX_HOBBIES) { printf("ERROR! Invalid hobby count for %s, exiting now!\n", personList[persons].name); exit(1); } for(i = 0; i < personList[persons].hobbyCount; i++) { fscanf(fPerson, "%s", personList[persons].hobbies[i]); } persons++; if(persons > limit) { fprintf(stderr, "ERROR! Input file is too long! ALlowed " "limit is %d entries. Reading of the " "file has stopped, continuing within " "a partial dataset\n", limit); break; } } fclose(fPerson); return persons; }
问题根源
以Sarah的条目为例,标注的爱好数量是2,但实际有4个爱好。程序按标注的数量读取2个爱好后,剩余的Writing Dancing会留在输入缓冲区中。下一次执行fscanf读取下一条数据时,会把Writing当作姓名、Dancing当作国家,后续数据全部错位,导致fscanf返回值不等于5,读取循环直接终止,程序停止处理后续条目。
修复方案
方案1:修正输入数据
确保每条数据的爱好数量与实际爱好个数完全一致,比如将Sarah条目的爱好数量改为4,或删除多余的两个爱好。这是最直接的解决方式。
方案2:添加代码容错处理
如果无法保证输入数据完全规范,可以在读完当前条目的爱好后,清空输入缓冲区中当前行的剩余内容,避免影响下一次读取。修改ReadPersonData函数,在persons++;之前添加以下代码:
// 跳过当前行剩余的所有字符,避免残留数据干扰下一次读取 int c; while ((c = fgetc(fPerson)) != '\n' && c != EOF);
同时,建议在读取爱好时增加返回值检查,确保读取操作成功:
int c; for(i = 0; i < personList[persons].hobbyCount; i++) { // 检查爱好读取是否成功 if (fscanf(fPerson, "%s", personList[persons].hobbies[i]) != 1) { fprintf(stderr, "Warning: Failed to read hobby for %s\n", personList[persons].name); // 跳过当前行剩余内容,避免影响后续读取 while ((c = fgetc(fPerson)) != '\n' && c != EOF); break; } } // 清空当前行剩余内容 while ((c = fgetc(fPerson)) != '\n' && c != EOF);
总结
核心问题是输入数据的爱好数量与实际个数不匹配,导致输入缓冲区残留数据破坏了后续读取逻辑。优先修正输入数据,若无法保证数据规范,则通过代码添加容错处理,清空当前行剩余内容即可解决问题。
内容的提问来源于stack exchange,提问作者CallMeSpec
相关产品推荐
相关产品推荐

