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

如何在C语言中读写结构体数组至二进制文件?代码问题求助

问题修复与优化方案

关键问题拆解

你的代码存在四个核心问题:

  • fwrite参数的正确性疑问
  • fgetpos/fsetpos的错误使用导致数据覆盖
  • 文件打开逻辑冗余且存在崩溃风险
  • 读取函数中feof的误用导致无效数据读取

逐一修复说明

1. fwrite中&符号的必要性

october[counter]是struct cinema类型的实体对象,fwrite要求传入数据的起始地址(const void*类型)。因此必须使用&october[counter]来获取结构体的地址,你的原写法是正确的。也可以写成october + counter,两者等价。

2. 移除多余的fgetpos/fsetpos操作

你每次调用new_cinema都会重新打开文件,而:

  • 使用ab模式打开文件时,文件指针默认定位在文件末尾,无需手动调整
  • 保存并复用current_position会导致后续写入覆盖之前的数据,完全是多余且危险的操作。直接删除所有fgetpos和fsetpos相关代码即可。

3. 写入函数的优化与修复

原文件打开逻辑冗余,且错误处理存在崩溃风险(fopen_s失败时调用fclose(NULL))。优化后的代码如下:

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

#define N 25  // 补充缺失的宏定义

struct cinema
{
    char name[256];
    char session[256];
    double price;
    int audience;
};

struct cinema october[N];  
int counter = 0;

void new_cinema()
{
    if (counter >= N)
    {
        printf("\nThe limit has gone!\n");
        return;
    }

    FILE* file;  // 使用局部文件指针替代全局指针,避免资源冲突
    if (fopen_s(&file, "file.bin", "ab") != 0)
    {
        printf("\nError opening file!\n");
        return;
    }

    // 清除之前scanf残留的换行符,避免gets_s直接读取空行
    while(getchar() != '\n');
    printf("\nWrite the name of the movie:\n");
    gets_s(october[counter].name, 255);
    
    printf("\nEnter the session time:\n");
    scanf_s("%s", october[counter].session, 255);
    
    printf("\nEnter ticket price:\n");
    scanf_s("%lf", &october[counter].price);
    
    printf("\nEnter the number of viewers:\n");
    scanf_s("%d", &october[counter].audience);

    // 写入结构体数据,校验写入结果
    if (fwrite(&october[counter], sizeof(struct cinema), 1, file) != 1)
    {
        printf("\nFailed to write data!\n");
    }
    else
    {
        counter++;
    }

    fclose(file);
}

4. 读取函数的修复

原读取函数使用while(!feof(file))会导致多读取一次空数据(feof仅在读取失败后才会置位),同时需要优化内存分配和遍历逻辑:

void read_struct()
{
    FILE* file;
    if (fopen_s(&file, "file.bin", "rb") != 0)
    {
        printf("\nCouldn't read the file!\n");
        return;
    }

    struct cinema *testing = malloc(sizeof(struct cinema) * N);
    if (testing == NULL)
    {
        printf("\nMemory allocation failed!\n");
        fclose(file);
        return;
    }

    int read_count = 0;
    // 以fread的返回值作为循环条件,判断是否成功读取一个结构体
    while (fread(&testing[read_count], sizeof(struct cinema), 1, file) == 1)
    {
        read_count++;
    }

    // 仅遍历实际读取到的数据
    for (int i = 0; i < read_count; i++)
    {
        printf("\nMovie Name: %s\n", testing[i].name);
        printf("Session Time: %s\n", testing[i].session);
        printf("Ticket Price: %.2lf\n", testing[i].price);
        printf("Number of Viewers: %d\n", testing[i].audience);
    }

    free(testing);
    fclose(file);
}

额外注意事项

  • 必须补充#define N 25,否则原代码中的数组定义和条件判断会报错
  • 减少全局变量的使用,可将october和counter改为局部变量或通过函数参数传递
  • 输入缓冲区的清理:scanf_s读取后残留的换行符会干扰gets_s,必须手动清空
  • 二进制文件跨平台兼容性:结构体的内存对齐依赖编译器和平台,若需跨平台需手动序列化数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 09:40:28