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

C语言如何读写二进制文件及解决读取时出现的段错误问题

C语言二进制读写结构体段错误问题分析与修复

核心问题原因

  • 结构体包含指针成员,直接二进制写入无效:你定义的new_acc结构体里有char *initials, *name, *email, *acc_type四个指针成员,调用fwrite直接写结构体时,写入的是指针指向的内存地址值,而非地址对应的字符串内容。读取时,之前申请的字符串内存已经被释放,读取到的指针属于野指针,访问时直接触发段错误。
  • 内存申请大小错误:malloc(sizeof(new_acc.name))里的new_acc.name是char*类型,64位系统下大小仅为8字节,你用scanf读入最长100字符的内容时直接发生缓冲区溢出,属于未定义行为。
  • 读写逻辑错误:写入时循环写13次完全相同的结构体内容,读取时也循环读13次,属于无效逻辑,没有实际意义。
  • 文件打开模式错误:二进制文件读写需要加b标识,你用的"a"、"r"是文本模式,在部分系统下会出现字节转换问题,导致读写内容错乱。
  • 打印格式错误:printf("%s\n", new_acc.birth_day);里birth_day是struct date类型,不是字符串,用%s打印直接触发内存非法访问。

修复方案

第一步:修改结构体定义,把指针成员改成定长数组,避免指针序列化问题

struct date{  // 日期结构体
    int mm, dd, yyyy;
};

// 把所有字符串成员改成定长数组,确保整个结构体内容连续可直接序列化
struct Account {
    char initials[50], name[100], email[50], acc_type[20];  // 定长数组替代指针
    char id_num[11], occupation[25], address[100];
    int phone, acc_num, balance;
    struct date birth_day;
} new_acc;

第二步:删除错误的内存申请逻辑

原来的4行malloc和对应的free代码全部删掉,定长数组的内存已经包含在结构体的内存空间里,不需要单独申请。

第三步:修复写入逻辑

void create_new(void)
{
    system("clear");
    puts("Answer the questions to make a account");

    time_t l;
    srand((unsigned) time(&l));
    new_acc.acc_num = l;

    printf("Enter your full name: ");
    scanf(" %100[^\n]", new_acc.name);

    printf("Enter your name with initials: ");
    scanf(" %50[^\n]", new_acc.initials);

    printf("Enter your birthday (mm/dd/yyyy): ");
    scanf(" %d %d %d", &new_acc.birth_day.mm, &new_acc.birth_day.dd, &new_acc.birth_day.yyyy);

    printf("Enter your address: ");
    scanf(" %100[^\n]", new_acc.address);

    printf("Enter your phone number: ");
    scanf(" %10d", &new_acc.phone);

    printf("Enter your id number: ");
    scanf(" %10[0-9a-zA-Z]", new_acc.id_num);

    printf("Enter your occupation: ");
    scanf(" %50[^\n]", new_acc.occupation);

    printf("Enter your email address:");
    scanf(" %49s", new_acc.email);

    printf("Enter the account type:\n");
    printf("\t#Saving\n\tFixed (1 year)\n\tFixed (2 year)\n\tFixed (3 year)\n");
    scanf(" %19s", new_acc.acc_type);

    printf("Enter amount to deposite: $");
    scanf(" %d", &new_acc.balance);

    // 二进制追加模式打开文件
    FILE *fp = fopen("employees", "ab");
    if (fp == NULL) {
        puts("Cannot open a file...");
        return;
    }
    // 单次写入即可,不需要循环写13次
    fwrite(&new_acc, sizeof(new_acc), 1, fp);
    fclose(fp);

    int out;
    printf("Successfully created a account!\nYour account number is %d\n", new_acc.acc_num);
    printf("Press 1 to exit, and 0 to go to main menu...");
    scanf("%d", &out);

    switch (out){
    case 1:
        exit(0);
        break;
    case 0:
        menu();
        break;
    }
}

第四步:修复读取逻辑

FILE *fp = fopen("employees", "rb"); // 二进制读模式打开
if (fp == NULL) {
    puts("Cannot open a file...");
    return;
}
// 如果要读最后一条记录,先把文件指针移到最后一条的位置
fseek(fp, -sizeof(new_acc), SEEK_END);
fread(&new_acc, sizeof(new_acc), 1, fp);
fclose(fp);

printf("%d\n", new_acc.acc_num);
printf("%s\n", new_acc.name);
printf("%s\n", new_acc.initials);
// 分开打印日期成员
printf("%d/%d/%d\n", new_acc.birth_day.mm, new_acc.birth_day.dd, new_acc.birth_day.yyyy);
printf("%s\n", new_acc.address);
printf("%d\n", new_acc.phone);
printf("%s\n", new_acc.id_num);
printf("%s\n", new_acc.occupation);
printf("%s\n", new_acc.email);
printf("%s\n", new_acc.acc_type);
printf("%d\n", new_acc.balance);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 20:06:05