[英]C file Fwrite and fread struct pointers
该程序仅适用于第一次。 第二次应该发生的是将相同的数据添加到二进制文件,但没有发生。
第一次运行:运行正常,显示写入文件。
第二次运行:它写入文件但不读取。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name, *role, *course;
int year, id;
} StudentFile;
void saveBin(StudentFile *studentsFile, int lines){
FILE *file = fopen("studentsx.bin","ab");
if (!file) {
printf("\n\n\tImposible to open file. \n\n");
exit(1);
}
for (int i = 0; i < lines; i++){
fwrite(&studentsFile[i], sizeof(StudentFile), 1, file);
}
fclose(file);
}
void readBin(){
StudentFile *studentsFile = malloc(sizeof(StudentFile)*5000);
FILE *file = fopen("studentsx.bin","rb");
if (!file) {
printf("\n\n\tImposible to open file. \n\n");
exit(1);
}
int j = 0;
while (fread(&studentsFile[j], sizeof(StudentFile), 1, file)){
printf("\nLine read %d: %s\t%s\t%d\t%d\t%s", j+1, studentsFile[j].name, studentsFile[j].role, studentsFile[j].year, studentsFile[j].id, studentsFile[j].course);
j++;
}
fclose(file);
}
void main(){
StudentFile *studentsFile = malloc(sizeof(StudentFile)*2);
int lines = 0;
studentsFile[0].name = "John";
studentsFile[0].role = "Gamer";
studentsFile[0].year = 1999;
studentsFile[0].id = 1;
studentsFile[0].course = "IOT";
studentsFile[1].name = "Piter";
studentsFile[1].role = "GamerXL";
studentsFile[1].year = 1991;
studentsFile[1].id = 2;
studentsFile[1].course = "IOTXL";
lines = 2;
saveBin(studentsFile, lines);
readBin();
}
您正在编写指针,而不是字符串。 fwrite
写入 memory 的单个连续数组。在您的情况下, StudentFiles
和实际字符串分散在 static memory 和堆 memory 中。
考虑你的结构:
typedef struct {
char *name, *role, *course;
int year, id;
} StudentFile;
在 memory 中看起来像这样:
[<pointer to name><pointer to role><pointer to course><year><id>]
memory 不同区块的其他地方:
[John\0Gamer\0\OIT\o.......]
你写了上面的第一个块而遗漏了第二个块。
这个问题有多种方法,我们通常将它们命名为“序列化”——将复杂的数据结构序列化为一个线性文件。
其中一种方法是在您的结构StudentFile
中分配固定大小的块:
#define MAX_NAME 100
#define MAX_ROLE 100
#define MAX_COURSE 100
typedef struct {
char name[MAX_NAME];
char role[MAX_ROLE];
char course[MAX_COURSE];
int year, id;
} StudentFile;
然后字符串name
、 role
和course
将在StudentFile
:
[<100 bytes for name><100 bytes for role><100 bytes for course><year><id>]
这是 memory 的连续块,如果可以像您一样使用单次调用 fwrite 来编写。
但是您将无法像以前那样分配字符串
studentsFile[i].name = "John";
C 为此有 strncpy:
strcpy(studentsFile[0].name, "John", MAX_NAME);
另一种方法是多次调用 fwrite。 对于每个字符串,首先写入长度,然后是字符串本身。 对于像int
这样的基本类型,您只需编写 int 即可。
首先,您从指针指向的不同位置收集字符串:
size_t nameLen = strlen(studentsFile[i].name) + 1;/* +1 for the final zero*/
fwrite(&nameLen, sizeof(size_t), 1, file);
fwrite(studentsFile[i].name, nameLen, 1, file);
size_t roleLen = strlen(studentsFile[i].role) + 1;
fwrite(&roleLen, sizeof(size_t), 1, file);
fwrite(studentsFile[i].role, roleLen, 1, file);
size_t courseLen = strlen(studentsFile[i].course) + 1;
fwrite(&courseLen, sizeof(size_t), 1, file);
fwrite(studentsFile[i].course, courseLen, 1, file);
然后你写原始类型:
fwrite(&studentsFile[i].year, sizeof(int), 1, file);
fwrite(&studentsFile[i].id, sizeof(int), 1, file);
下次读取文件时,您将依赖写入顺序并以相同顺序读回字段:
size_t nameLen;
fread(&nameLen, sizeof(size_t), 1, file);
char *name = malloc(nameLen);
fread(name, nameLen, 1, file);
size_t roleLen;
fread(&roleLen, sizeof(size_t), 1, file);
char *role = malloc(roleLen);
fread(role, roleLen, 1, file);
size_t courseLen;
fread(&courseLen, sizeof(size_t), 1, file);
char *course = malloc(courseLen);
fread(course, courseLen, 1, file);
int year;
fread(&year, sizeof(int), 1, file);
int id;
fread(&id, sizeof(int), 1, file);
printf("\nLine read %d: %s\t%s\t%d\t%d\t%s", j+1, name, role, year, id, course);
问题出在其他地方:仔细想想,你的代码在这里用fwrite()
做什么?
typedef struct {
char *name, *role, *course;
int year, id;
} StudentFile;
fwrite(&studentsFile[i], sizeof(StudentFile), 1, file);
从studentFile
写入单个元素后,文件内容是什么样的?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.