将结构写入二进制文件,然后读取文件并打印数据。
Write struct to binary file, then read file and print data.
我正在自学 C 并试图了解内存分配和基本 I/O。我的代码创建了一个 "database" 对象,其中包含一个指向 "address" 结构的指针。我将最后一个指针用作数组,并为其分配所需的 space。我将数据写入文件,然后打开文件以读回数据。 Valgrind 显示没有内存问题。
但是,当在 Windows 7(使用 MingW gcc 4.8.1 构建)上构建和 运行 时,它会在尝试读取文件时死机。另外,在win 7下,如果我给MAX_ROWS取值为26,程序就会进入死循环
此外,我不确定这段代码的efficiency/correctness。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_ROWS 1000 * 1000
#define MAX_DATA 512
typedef struct Address {
int id;
int set;
char *name;
char *email;
} Address;
typedef struct Database {
int max_rows;
int max_data;
Address *rows;
} Database;
int main(int argc, char *argv[])
{
Database *db = malloc(sizeof(Database));
if(db == NULL) {
printf("Could not allocate mem for db");
free(db);
exit(1);
}
db->max_data = MAX_DATA;
db->max_rows = MAX_ROWS;
db->rows = malloc(sizeof(Address) * db->max_rows);
if(db->rows == NULL) printf("Could not allocate mem for db->rows");
// Create static data
for(int i = 0; i < MAX_ROWS; i++) {
Address addr = { .id = i, .name = "Jack Sparrow", .email = "jacksp@example.com"};
// Assign it
*(db->rows + i) = addr;
}
// Open a file to write the data
FILE *f = fopen("temp.dat", "w+");
if(!f) printf("Could not open file");
// The reason I cannot write the struct in one move
// is because it has been dynamically sized
int rc = fwrite(&db->max_rows, sizeof(int), 1, f);
rc = fwrite(&db->max_data, sizeof(int), 1, f);
rc = fwrite(db->rows, sizeof(Address) * db->max_rows, 1, f);
if(!rc) printf("could not write db");
fclose(f);
free(db->rows);
free(db);
// Now let's read the file
f = fopen("temp.dat", "r");
if(!f) printf("Could not open file\n");
// Create a new Database pointer to store file data
Database *tmpdb = malloc(sizeof(Database));
if(!tmpdb) printf("could not allocate memory to tmpdb\n");
rc = fread(&tmpdb->max_rows, sizeof(int) , 1, f);
if(!rc) printf("could not read max_rows\n");
rc = fread(&tmpdb->max_data, sizeof(int) , 1, f);
if(!rc) printf("could not read max_data\n");
printf("%d\n", tmpdb->max_rows);
tmpdb->rows = malloc(sizeof(Address) * tmpdb->max_rows);
if(!tmpdb->rows) printf("could not allocate rows\n");
// This dies on windows (MingW gcc), but runs fine on ubuntu!
rc = fread(tmpdb->rows, sizeof(Address) * tmpdb->max_rows , 1, f);
if(!rc) printf("could not read db\n");
fclose(f);
free(tmpdb->rows);
free(tmpdb);
return 0;
}
您必须以二进制模式打开文件,例如"wb+"
和 "rb"
。这是因为(尤其是 Windows),二进制文件和文本文件不一样。
另外,像这样的一行
fwrite(&db->max_rows, sizeof(int), 1, f);
最好写成
fwrite(&db->max_rows, sizeof db->max_rows, 1, f);
这避免了对 max_rows
的类型名称进行硬编码,因此即使要更改代码也不会中断。少了一个记得改的地方,少了一个依赖。
并且您正在覆盖 rc
return 值,因此您不会真正正确地捕获错误。
最后,请注意,像这样执行二进制 I/O 意味着文件将不可移植,因为它将取决于 endianess 和编写它的编译器的确切类型大小选择.
我正在自学 C 并试图了解内存分配和基本 I/O。我的代码创建了一个 "database" 对象,其中包含一个指向 "address" 结构的指针。我将最后一个指针用作数组,并为其分配所需的 space。我将数据写入文件,然后打开文件以读回数据。 Valgrind 显示没有内存问题。
但是,当在 Windows 7(使用 MingW gcc 4.8.1 构建)上构建和 运行 时,它会在尝试读取文件时死机。另外,在win 7下,如果我给MAX_ROWS取值为26,程序就会进入死循环
此外,我不确定这段代码的efficiency/correctness。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_ROWS 1000 * 1000
#define MAX_DATA 512
typedef struct Address {
int id;
int set;
char *name;
char *email;
} Address;
typedef struct Database {
int max_rows;
int max_data;
Address *rows;
} Database;
int main(int argc, char *argv[])
{
Database *db = malloc(sizeof(Database));
if(db == NULL) {
printf("Could not allocate mem for db");
free(db);
exit(1);
}
db->max_data = MAX_DATA;
db->max_rows = MAX_ROWS;
db->rows = malloc(sizeof(Address) * db->max_rows);
if(db->rows == NULL) printf("Could not allocate mem for db->rows");
// Create static data
for(int i = 0; i < MAX_ROWS; i++) {
Address addr = { .id = i, .name = "Jack Sparrow", .email = "jacksp@example.com"};
// Assign it
*(db->rows + i) = addr;
}
// Open a file to write the data
FILE *f = fopen("temp.dat", "w+");
if(!f) printf("Could not open file");
// The reason I cannot write the struct in one move
// is because it has been dynamically sized
int rc = fwrite(&db->max_rows, sizeof(int), 1, f);
rc = fwrite(&db->max_data, sizeof(int), 1, f);
rc = fwrite(db->rows, sizeof(Address) * db->max_rows, 1, f);
if(!rc) printf("could not write db");
fclose(f);
free(db->rows);
free(db);
// Now let's read the file
f = fopen("temp.dat", "r");
if(!f) printf("Could not open file\n");
// Create a new Database pointer to store file data
Database *tmpdb = malloc(sizeof(Database));
if(!tmpdb) printf("could not allocate memory to tmpdb\n");
rc = fread(&tmpdb->max_rows, sizeof(int) , 1, f);
if(!rc) printf("could not read max_rows\n");
rc = fread(&tmpdb->max_data, sizeof(int) , 1, f);
if(!rc) printf("could not read max_data\n");
printf("%d\n", tmpdb->max_rows);
tmpdb->rows = malloc(sizeof(Address) * tmpdb->max_rows);
if(!tmpdb->rows) printf("could not allocate rows\n");
// This dies on windows (MingW gcc), but runs fine on ubuntu!
rc = fread(tmpdb->rows, sizeof(Address) * tmpdb->max_rows , 1, f);
if(!rc) printf("could not read db\n");
fclose(f);
free(tmpdb->rows);
free(tmpdb);
return 0;
}
您必须以二进制模式打开文件,例如"wb+"
和 "rb"
。这是因为(尤其是 Windows),二进制文件和文本文件不一样。
另外,像这样的一行
fwrite(&db->max_rows, sizeof(int), 1, f);
最好写成
fwrite(&db->max_rows, sizeof db->max_rows, 1, f);
这避免了对 max_rows
的类型名称进行硬编码,因此即使要更改代码也不会中断。少了一个记得改的地方,少了一个依赖。
并且您正在覆盖 rc
return 值,因此您不会真正正确地捕获错误。
最后,请注意,像这样执行二进制 I/O 意味着文件将不可移植,因为它将取决于 endianess 和编写它的编译器的确切类型大小选择.