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

C语言读取含结构体数组的结构体二进制文件遇段错误问题

问题根源

你遇到的段错误是因为Movie结构体里的View *Views是指针类型——当你把Movie结构体写入二进制文件时,保存的只是这个指针在内存中的地址值,而不是它指向的View数组实际数据。读取时,这个地址在当前进程的内存空间里是无效的(要么未分配,要么属于其他内存区域),直接访问movie.Views[i]自然会触发段错误。

修复方案

要正确读取这类包含动态数组的结构体,需要分两步读取:先读取Movie的非指针部分,再根据CountView的值动态分配内存,最后读取对应数量的View数据。

修复后的读取代码

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

// 假设MAX_LINE_SIZE是已定义的常量,这里示例定义为256
#define MAX_LINE_SIZE 256

typedef struct view
{
    long CustomerID;
    int Rating;
    char Date[11];
} View;

typedef struct movie
{
    long MovieID;
    long YearOfRelease;
    char Title[MAX_LINE_SIZE];
    long CountView;
    View *Views; // 动态数组指针,读取时需单独分配内存
} Movie;

void readDataFromBinary()
{
    FILE *f = fopen("../saved_data/save_data.bin", "rb");
    if (f == NULL)
    {
        perror("fopen");
        exit(EXIT_FAILURE);
    }

    Movie movie;
    // 先读取Movie的固定长度非指针成员,以MovieID作为读取循环的判断依据
    while (fread(&movie.MovieID, sizeof(long), 1, f) == 1)
    {
        // 依次读取其他非指针成员
        fread(&movie.YearOfRelease, sizeof(long), 1, f);
        fread(movie.Title, sizeof(char), MAX_LINE_SIZE, f);
        fread(&movie.CountView, sizeof(long), 1, f);

        // 根据CountView分配对应大小的内存
        movie.Views = malloc(movie.CountView * sizeof(View));
        if (movie.Views == NULL)
        {
            perror("malloc");
            fclose(f);
            exit(EXIT_FAILURE);
        }

        // 一次性读取所有View数组数据
        fread(movie.Views, sizeof(View), movie.CountView, f);

        // 打印读取到的数据
        printf("MovieId : %ld\n", movie.MovieID);
        printf("YearOfRelease : %ld\n", movie.YearOfRelease);
        printf("Title : %s", movie.Title);
        printf("CountView : %ld\n\n", movie.CountView);

        for (int i = 0; i < movie.CountView; i++)
        {
             printf("%ld\n", movie.Views[i].CustomerID);
             printf("%d\n", movie.Views[i].Rating);
             printf("%s\n", movie.Views[i].Date);
        }

        // 释放动态分配的内存,避免内存泄漏
        free(movie.Views);
        movie.Views = NULL;
    }

    if (fclose(f) == -1)
    {
        perror("fclose");
        exit(EXIT_FAILURE);
    }
}

关键注意事项

  • 对应的写入代码必须同步修改:不能直接用fwrite(&movie, sizeof(Movie), 1, f)写入整个结构体,而是要分两部分写入——先写Movie的非指针成员,再写Views指向的数组数据。示例写入逻辑如下:
void writeDataToBinary(Movie *movies, int movieCount)
{
    FILE *f = fopen("../saved_data/save_data.bin", "wb");
    if (f == NULL)
    {
        perror("fopen");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < movieCount; i++)
    {
        Movie *m = &movies[i];
        // 写入非指针成员
        fwrite(&m->MovieID, sizeof(long), 1, f);
        fwrite(&m->YearOfRelease, sizeof(long), 1, f);
        fwrite(m->Title, sizeof(char), MAX_LINE_SIZE, f);
        fwrite(&m->CountView, sizeof(long), 1, f);
        // 写入View数组的实际数据
        fwrite(m->Views, sizeof(View), m->CountView, f);
    }

    fclose(f);
}
  • 如果你的二进制文件是用fwrite(&movie, sizeof(Movie), 1, f)直接写入的,那这个文件只保存了指针地址,没有实际的View数据,这种情况下无法恢复数据,必须重新用正确的写入逻辑生成新的二进制文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 04:10:17