You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法从二进制文件正确读取结构体数据,求技术修复方案

问题修复方案

首先,你的程序出现ptr[0][0].Flat_ID输出随机数的核心原因是在memalloc函数中提前关闭了文件,导致后续读取结构体的操作使用了无效的文件指针,同时还有几个其他关键bug影响程序运行,下面逐一解决:


1. 致命错误:memalloc中提前关闭文件导致读取无效

在你的memalloc函数中,读取完floors和flats_per_floor后立刻关闭了文件,后续尝试用已经关闭的f指针读取结构体,这会触发未定义行为(比如读取随机垃圾值)。同时还存在双重关闭文件的问题。

错误代码片段:

fread(&floors,sizeof(unsigned),1,f);
fread(&flats_per_floor,sizeof(unsigned),1,f);
fclose(f); // 提前关闭文件!
// 后续用无效的f指针读取结构体
for(int i = 0; i < floors; i++) {
    for(int j = 0; j < flats_per_floor; j++) {
        fread(&Apartment,sizeof(S_Apartament),1,f);
        arr[i][j]=Apartment;
    }
}
fclose(f); // 再次关闭已关闭的文件,触发错误

修复后的memalloc函数:

S_Apartament** memalloc(unsigned int *floors, unsigned int *flats_per_floor, S_Apartament Apartment, char FileName[50]) {
    FILE *f = fopen(FileName,"rb");
    if(f==NULL) {
        printf("Error opening file, or no such file.\n");
        // 注意:f为NULL时不能调用fclose,直接退出即可
        exit(1);
    }
    // 读取楼层和每层户数(用指针传递,让main函数的变量也能更新)
    fread(floors, sizeof(unsigned int), 1, f);
    fread(flats_per_floor, sizeof(unsigned int), 1, f);

    // 分配二维数组内存
    S_Apartament **arr = (S_Apartament **)malloc(sizeof(S_Apartament*) * *floors);
    for (int i = 0; i < *floors; i++) {
        arr[i] = (S_Apartament *)malloc(sizeof(S_Apartament) * *flats_per_floor);
    }

    // 读取所有结构体(此时文件仍处于打开状态)
    for(int i = 0; i < *floors; i++) {
        for(int j = 0; j < *flats_per_floor; j++) {
            fread(&arr[i][j], sizeof(S_Apartament), 1, f);
        }
    }

    fclose(f); // 所有读取完成后再关闭文件
    return arr;
}

2. 关键错误:值传递导致main中floors和flats_per_floor未更新

你在main中调用memalloc时传递的是floors和flats_per_floor的初始值0,而C语言是值传递,memalloc内部修改的只是局部变量,main中的变量不会被更新,导致后续调用enterNewResidents等函数时使用的是错误的0值。

修复main中的调用:

// 把原来的调用改成传递指针
S_Apartament **ptr = memalloc(&floors, &flats_per_floor, Flats, FileName);
// 此时floors和flats_per_floor已经被正确更新为文件中的值
printf("%u\n", ptr[0][0].Flat_ID);

同时修改Header.h中的函数声明:

// 把参数改成指针类型
S_Apartament** memalloc(unsigned int *floors, unsigned int *flats_per_floor, S_Apartament Apartment, char FileName[50]);

3. 循环条件错误:calculateTax中的无限循环风险

在calculateTax函数中,内层循环的条件写错了,用了i<flats_per_floor而不是j<flats_per_floor,这会导致无限循环或者数组越界。

错误代码:

for(int j=0; i<flats_per_floor; j++) {

修复后:

for(int j=0; j<flats_per_floor; j++) {

4. 错误处理优化:避免关闭NULL指针

在memalloc和writeInfo中,当fopen失败时,你尝试关闭NULL指针,这会触发未定义行为,应该直接退出而不调用fclose。

修复writeInfo中的错误处理:

if(fp==NULL) {
    printf("Error opening file\n");
    // 去掉fclose(fp),因为fp是NULL
    exit(2);
}

5. emptyApartment中的越界访问风险

当找到目标公寓后,内层循环break,此时j的值等于flats_per_floor,外层循环中ptr[i][j]会访问数组越界,建议用标志位来控制循环:

修复后的emptyApartment:

void emptyApartment(S_Apartament **ptr, unsigned floors, unsigned flats_per_floor) {
    unsigned short Entered_number = 0;
    int i = 0, j = 0;
    int found = 0; // 标志位,标记是否找到公寓
    printf("Enter the number of the apartment you wish to empty:\n");
    scanf("%hu", &Entered_number);
    for(i=0; i<floors; i++) {
        for(j=0; j<flats_per_floor; j++) {
            if(Entered_number == ptr[i][j].Flat_ID) {
                ptr[i][j].count_Adults = 0;
                ptr[i][j].count_Children = 0;
                ptr[i][j].Family_Surname[0] = '\0';
                ptr[i][j].rent = 0.00;
                printf("Apartment is empty\n");
                found = 1;
                break;
            }
        }
        if(found) {
            break;
        }
    }
    if(!found) {
        printf("No such apartment\n");
    }
}

最后:main中的内存释放问题

你在menu循环内部调用了free(ptr);,但如果用户多次选择菜单命令,ptr会被提前释放,后续操作会访问已释放的内存。应该把free(ptr);移到menu循环结束之后:

while(1) {
    choice = menu();
    if(choice==0) {
        break;
    }
    switch(choice) {
        case 1: enterNewResidents(ptr, floors, flats_per_floor); break;
        case 2: calculateTax(ptr, floors, flats_per_floor); break;
        case 3: Elevator(ptr, floors, flats_per_floor); break;
        case 4: emptyApartment(ptr, floors, flats_per_floor); break;
        default: printf("Invalid command\n"); break;
    }
    writeInfo(ptr,floors,flats_per_floor, FileName);
}
free(ptr); // 移到循环外面,避免提前释放

经过以上修复后,你的程序应该能正确读取二进制文件中的结构体数据,ptr[0][0].Flat_ID会输出预期的101,其他功能也能正常运行。

内容的提问来源于stack exchange,提问作者Jordan Baller

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 19:22:31