将结构写入二进制文件,然后读取文件并打印数据。

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 和编写它的编译器的确切类型大小选择.