含内部结构体指针的结构体如何单次用fwrite/fread读写二进制文件
C语言含动态指针的结构体二进制单次读写解决方案
问题背景
在C语言中处理结构体的二进制文件读写时,两种结构体的表现存在明显差异:
- 含固定
Point数组的Path_array结构体,直接用fwrite()/fread()单次读写整个结构体即可正常工作。 - 含
Point指针的Path_pointer结构体,直接读写结构体本身会失败,最初怀疑是fwrite()/fread()的第二个参数设置问题,但实际原因并非如此。
失败原因
Path_array中的数组是结构体的一部分,内存地址连续,因此单次写入整个结构体时,数组的所有数据会被一并写入文件;而Path_pointer中的指针仅存储了动态分配内存的地址,直接写入结构体时,只会把这个内存地址写入文件,而非指针指向的实际数据。读取时,这个地址在当前进程中无效,导致无法正确恢复数据。
正确单次读写方法
要实现含动态指针结构体的单次二进制读写,需要将结构体的元数据(如数据长度)和指针指向的实际数据合并为连续的内存块进行操作:
- 写入时:把结构体的固定字段(如长度)和指针指向的数据拷贝到一块连续临时内存,再一次性写入文件。
- 读取时:先读取元数据(长度),根据长度分配对应内存,再一次性读取数据到分配好的内存中。
示例代码
首先定义基础结构体:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int x; int y; } Point; // 含固定数组的结构体(可直接单次读写) typedef struct { int len; Point points[100]; } Path_array; // 含动态指针的结构体(需特殊处理) typedef struct { int len; Point *points; } Path_pointer;
写入含指针的结构体(单次操作)
int write_path(FILE *fp, const Path_pointer *path) { if (!fp || !path || !path->points) return -1; // 计算总数据大小:长度字段 + 所有Point数据 size_t total_size = sizeof(path->len) + path->len * sizeof(Point); char *buf = malloc(total_size); if (!buf) return -1; // 将长度和数据拷贝到连续内存 memcpy(buf, &path->len, sizeof(path->len)); memcpy(buf + sizeof(path->len), path->points, path->len * sizeof(Point)); // 单次写入所有数据 size_t written = fwrite(buf, 1, total_size, fp); free(buf); return written == total_size ? 0 : -1; }
读取含指针的结构体(单次操作)
int read_path(FILE *fp, Path_pointer *path) { if (!fp || !path) return -1; // 先读取长度字段 size_t read_len = fread(&path->len, sizeof(path->len), 1, fp); if (read_len != 1) return -1; // 根据长度分配内存 path->points = malloc(path->len * sizeof(Point)); if (!path->points) return -1; // 单次读取所有Point数据 size_t read_data = fread(path->points, sizeof(Point), path->len, fp); return read_data == path->len ? 0 : -1; }
与其他相关帖子的区别
- 本方案针对动态内存分配的结构体,解决了单次读写的核心需求,而非逐个元素操作。
- 其他相关帖子大多未给出基于
fwrite()/fread()的完整单次读写解决方案,要么仅讨论问题原因,要么采用逐元素读写的方式,无法满足一次性读写的需求。
内容的提问来源于stack exchange,提问作者ckc
相关产品推荐
相关产品推荐

