[英]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.