我正在自学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;
}
答案 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以及编写它的编译器的确切类型大小选择。