You need to enable JavaScript to run this app. C语言二进制文件读写及人员数据自动加载功能异常问题
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.07 07:54:02