将struct写入二进制文件,然后读取文件和打印数据。

时间:2015-04-21 09:27:07

标签: c gcc malloc mingw fread

我正在自学C并尝试了解内存分配和基本I / O.我的代码创建了一个“数据库”对象,其中包含一个指向“地址”结构的指针。我用作数组的最后一个指针,并为其分配所需的空间。我将数据写入文件,然后打开文件以读回数据。 Valgrind没有显示内存问题。

但是,当在Windows 7(使用MingW gcc 4.8.1构建)上构建和运行时,它会在尝试读取文件时死亡。此外,在win 7下,如果我给出MAX_ROWS值为26,程序将进入无限循环。

此外,我不确定这段代码的效率/正确性。

#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;
}

1 个答案:

答案 0 :(得分:2)

您必须以二进制模式打开文件,例如"wb+""rb"。这是因为(特别是在Windows上),二进制和文本文件不一样。

此外,还有一行

fwrite(&db->max_rows, sizeof(int), 1, f);

最好写成

fwrite(&db->max_rows, sizeof db->max_rows, 1, f);

这避免了对max_rows的类型名称进行硬编码,因此如果要更改代码则不会中断。记住改变的地方少了一个,而且依赖性减少了一个。

并且您正在覆盖rc返回值,因此您无法正确捕获错误。

最后,请注意执行这样的二进制I / O意味着该文件不可移植,因为它将取决于endianess以及编写它的编译器的确切类型大小选择。