C语言二进制文件读写及人员数据自动加载功能异常问题
二进制读写功能失效问题修正方案
一、核心Bug定位
- 写入流程错误
- 原代码用
ab+追加模式打开文件,和“将完整Persons结构体(含人数计数器、全量人员数组)作为单个对象持久化”的设计完全冲突 fwrite第一个参数传参错误:函数参数persons已经是Persons类型指针,原代码额外取地址传入&persons(指针的指针),实际写入的是指针变量本身的内存,而非真实的结构体数据fwrite其余参数传参错误:原代码以persons->counter为写入个数,实际应仅写入1个完整的Persons结构体- 写入结果判断逻辑完全失效:原代码判断
fwrite != 0是校验函数指针地址,永远为真,根本未校验实际写入的返回值 - 计数器自增逻辑错误:原代码用后置自增
return persons->counter++;,先返回旧值再更新计数器,导致后续计数逻辑混乱 - 人数上限未做校验:新增人员前没有判断是否超过
MAX_PERSON限制,会出现数组越界
- 原代码用
- 读取流程错误
- 原代码用
rb+模式打开文件,首次运行无文件时会直接崩溃退出,不符合预期 fread第一个参数传参错误:函数参数persons已经是Persons类型指针,原代码额外取地址传入&persons,读取的数据直接覆盖了指针变量本身,完全没有写入实际的结构体内存fread其余参数传参错误:原代码以初始值为0的counter作为读取个数,实际应直接读取1个完整的Persons结构体,无需依赖counter值
- 原代码用
- 编译级错误
searchPeople中使用未定义的宏ERROR_PERSON_NOT_EXISTS,无定义会直接编译失败printPerson、searchPerson在调用前未做前置声明,会触发隐式声明编译警告
二、修正后完整可运行代码
#include <stdio.h> #include <stdlib.h> #define MAX_PERSON 3 #define FILENAME "person.bin" #define ERROR_PERSON_NOT_EXISTS "人员不存在" typedef struct { int id; char fname[20],lname[20]; }person; typedef struct { int counter; person persons[MAX_PERSON]; }Persons; // 前置声明 void printPerson(person person); int searchPerson(Persons persons,int number); int writeStruct(Persons *persons,char *file){ // 校验人数上限 if (persons->counter >= MAX_PERSON) { puts("人员数量已达上限,无法新增"); return persons->counter; } FILE *outfile; // 用wb模式覆盖写入完整结构体 outfile = fopen(file, "wb"); if (outfile == NULL){ perror("打开写入文件失败"); exit(EXIT_FAILURE); } printf("\n请输入人员信息\n"); printf("编号: "); scanf("%d", &persons->persons[persons->counter].id); printf("名: "); scanf("%s", persons->persons[persons->counter].fname); printf("姓: "); scanf("%s", persons->persons[persons->counter].lname); // 更新计数器后写入完整结构体 persons->counter++; size_t write_flag = fwrite(persons, sizeof(Persons), 1, outfile); if(write_flag == 1){ puts("文件写入成功"); }else{ puts("文件写入失败"); } fclose(outfile); return persons->counter; } void loadStruct(Persons *persons,char *file){ FILE *infile; // 用rb只读模式打开,无文件时直接初始化空数据 infile = fopen(file, "rb"); if (infile == NULL) { persons->counter = 0; return; } // 读取完整结构体,仅读1个对象 size_t read_flag = fread(persons, sizeof(Persons), 1, infile); // 读取失败时重置计数器 if (read_flag != 1) { persons->counter = 0; } fclose(infile); } void listPersons(Persons persons){ int i; puts("人员列表"); puts("-----------------"); for(i=0;i < persons.counter; i++) { printPerson(persons.persons[i]); } puts("-----------------"); } void searchPeople(Persons persons) { int number; printf("请输入要查询的人员编号: "); scanf("%d",&number); number = searchPerson(persons,number); if (number != -1) { printPerson(persons.persons[number]); } else { puts(ERROR_PERSON_NOT_EXISTS); } } int searchPerson(Persons persons,int number) { int i; for (i = 0; i < persons.counter; i++) { if (persons.persons[i].id == number) { return i; } } return -1; } void printPerson(person person){ printf("%d - %s %s\n", person.id,person.fname, person.lname); } int main () { int op; Persons persons = {.counter = 0}; // 启动时加载本地文件数据 loadStruct(&persons,FILENAME); do{ puts("人员管理系统"); puts("-----------------"); puts("2 - 新增人员"); puts("3 - 人员列表"); puts("4 - 查询人员"); puts("0 - 退出系统"); puts("-----------------"); printf("当前人员数: %d/%d \n", persons.counter, MAX_PERSON); printf("请输入选项: "); scanf("%d",&op); printf("\n"); switch (op) { case 0: exit(0); break; case 2: writeStruct(&persons,FILENAME); break; case 3: listPersons(persons); break; case 4: searchPeople(persons); break; default: puts("无效选项!"); break; } }while(op!=0); return 0; }
三、修正后逻辑说明
- 每次新增人员后,会把包含最新计数器、全量人员数组的完整结构体整体写入文件,避免追加模式导致的数据错乱
- 启动时如果不存在本地二进制文件,会自动初始化为空人员列表,不会崩溃
- 所有读写操作都校验实际返回值,能准确提示读写成功/失败状态
- 新增前校验人数上限,避免数组越界
内容的提问来源于stack exchange,提问作者Pedro Carvalho
相关产品推荐
相关产品推荐

