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

Visual C读写含结构体数据的二进制文件时出现异常行为

程序错误分析与修复

你的代码存在多个核心错误,直接引发堆损坏、断点触发等问题,以下是具体问题和修复方案:

一、内存分配错误

所有涉及Employee数组的内存分配,都错误使用了sizeof(db->employee)——这是指针的大小(32位系统4字节,64位8字节),而非Employee结构体的实际大小。比如:

  • main中db->employee = (Employee*)malloc(db->size * sizeof(db->employee));
  • LoadDatabase中db->employee = (Employee*)malloc(n * sizeof(db->employee));
    修复:替换为sizeof(Employee)或sizeof(*db->employee),确保分配足够存储每个员工数据的内存。

二、二进制文件读写错误

保存数据时

SaveDatabase中fwrite(&db->employee, sizeof(db->employee), db->size, fp)是错误的:你写入的是指针变量的地址值,而非指针指向的员工数组数据。
修复:改为fwrite(db->employee, sizeof(Employee), db->size, fp),直接写入数组的实际内容。

加载数据时

LoadDatabase中fread(&db->employee, sizeof(db->employee), n, fp)同样错误:你试图把文件内容写入指针变量本身,而非指针指向的已分配内存。另外,加载后未给db->size赋值,后续循环会访问未初始化的垃圾值。
修复:改为fread(db->employee, sizeof(Employee), n, fp),同时添加db->size = n;赋值员工数量。

三、内存泄漏与文件打开错误处理

LoadDatabase中先malloc了db,再尝试打开文件,如果文件打开失败,直接返回NULL会导致db的内存无法释放,造成泄漏。
修复:先打开文件,确认成功后再mallocdb。

四、其他潜在问题

  • strcpy存在缓冲区溢出风险,建议替换为strncpy并手动添加字符串结束符;
  • printf中的/t是笔误,应该是\t制表符;
  • 所有malloc操作未做空指针检查,极端情况下会引发崩溃。

修复后的完整代码

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SAVE

typedef struct Employee
{
    char id[6];         
    char surname[20];
    char lastname[20]; 
    char firstname[20];
    unsigned int basic;
    unsigned int incentive;
    unsigned int salary;

} Employee;


typedef struct Database
{
    Employee* employee;
    unsigned int size;

} Database;

int SaveDatabase(const char* fileName, Database* db)
{
    FILE* fp = fopen(fileName, "wb");

    if (fp == NULL)
        return 1;

    if (fwrite(&db->size, sizeof(db->size), 1, fp) != 1)
    {
        fclose(fp);
        return 2;
    }

    if (fwrite(db->employee, sizeof(Employee), db->size, fp) != db->size)
    {
        fclose(fp);
        return 3;
    }

    fclose(fp);
    return 0;
}

Database* LoadDatabase(const char* fileName)
{
    FILE* fp = fopen(fileName, "rb");
    if (fp == NULL)
        return NULL;

    unsigned int n = 0;
    if (fread(&n, sizeof(n), 1, fp) != 1)
    {
        fclose(fp);
        return NULL;
    }

    Database* db = (Database*)malloc(sizeof(Database));
    if (db == NULL)
    {
        fclose(fp);
        return NULL;
    }

    db->employee = (Employee*)malloc(n * sizeof(Employee));
    if (db->employee == NULL)
    {
        free(db);
        fclose(fp);
        return NULL;
    }

    if (fread(db->employee, sizeof(Employee), n, fp) != n)
    {
        free(db->employee);
        free(db);
        fclose(fp);
        return NULL;
    }

    db->size = n;
    fclose(fp);
    return db;
}

int main(int argc, char* argv[])
{

#ifdef SAVE

    Database* db = (Database*)malloc(sizeof(Database));
    if (db == NULL)
        return 1;

    db->size = 2;
    db->employee = (Employee*)malloc(db->size * sizeof(Employee));
    if (db->employee == NULL)
    {
        free(db);
        return 1;
    }

    strncpy(db->employee[0].id, "1234", sizeof(db->employee[0].id)-1);
    db->employee[0].id[sizeof(db->employee[0].id)-1] = '\0';
    strncpy(db->employee[0].surname, "Bakshi", sizeof(db->employee[0].surname)-1);
    db->employee[0].surname[sizeof(db->employee[0].surname)-1] = '\0';
    strncpy(db->employee[0].lastname, "Vipin", sizeof(db->employee[0].lastname)-1);
    db->employee[0].lastname[sizeof(db->employee[0].lastname)-1] = '\0';
    strncpy(db->employee[0].firstname, "Byomkesh", sizeof(db->employee[0].firstname)-1);
    db->employee[0].firstname[sizeof(db->employee[0].firstname)-1] = '\0';
    db->employee[0].basic = 25000;
    db->employee[0].incentive = 25000;
    db->employee[0].salary = 50000;

    strncpy(db->employee[1].id, "1235", sizeof(db->employee[1].id)-1);
    db->employee[1].id[sizeof(db->employee[1].id)-1] = '\0';
    strncpy(db->employee[1].surname, "Chatterjee", sizeof(db->employee[1].surname)-1);
    db->employee[1].surname[sizeof(db->employee[1].surname)-1] = '\0';
    strncpy(db->employee[1].lastname, "Naren", sizeof(db->employee[1].lastname)-1);
    db->employee[1].lastname[sizeof(db->employee[1].lastname)-1] = '\0';
    strncpy(db->employee[1].firstname, "Basu", sizeof(db->employee[1].firstname)-1);
    db->employee[1].firstname[sizeof(db->employee[1].firstname)-1] = '\0';
    db->employee[1].basic = 35000;
    db->employee[1].incentive = 30000;
    db->employee[1].salary = 65000;


    SaveDatabase("Data.dat", db);
    free(db->employee);
    free(db);

#else

    Database* db = LoadDatabase("Data.dat");
    if (db == NULL)
    {
        printf("加载数据库失败\n");
        return 1;
    }

    for (unsigned int i = 0; i < db->size; i++)
    {
        printf("\n%s\t%s %s %s %u %u %u", 
               db->employee[i].id, 
               db->employee[i].firstname, 
               db->employee[i].lastname, 
               db->employee[i].surname,
               db->employee[i].basic, 
               db->employee[i].incentive, 
               db->employee[i].salary);
    }

    free(db->employee);
    free(db);

#endif // SAVE

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 15:47:40