因此,我目前正致力于Learn C the Hard Way并在练习17中坚持额外的功劳。
需要的是将固定大小的数据库从http://c.learncodethehardway.org/book/ex17.html转换为动态大小的数据库,其中您可以获取用户允许的行数和最大字符串长度。
我设法让程序创建数据库并将其写入文件,但我无法弄清楚如何再次从文件中读取程序。
程序正在编译,但每当我尝试做除了创建数据库之外的任何事情时,它都是分段的。我已经用valgrind检查了,直接原因似乎是从非分配内存中读取。我认为问题出在Database_load函数中,位于下面。
请注意,这是我第一次发帖提问,如果发帖太多,我会道歉。
加载它:
struct Connection *Database_open(const char *filename, char mode)
{
struct Connection *conn = malloc(sizeof(struct Connection));
if(!conn) die("Memory error", conn);
conn->db = malloc(sizeof(struct Database));
if(!conn->db) die("Memory error", conn);
// If we're creating, write a new file otherwise load it up.
if(mode == 'c') {
conn->file = fopen(filename, "w");
} else {
conn->file = fopen(filename, "r+");
if(conn->file) {
Database_load(conn);
}
}
if(!conn->file) die("Failed to open the file", conn);
return conn;
}
void Database_load(struct Connection *conn)
{
int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
if(rc != 1) die("Failed to load database.", conn);
const int MAX_ROWS = conn->db->MAX_ROWS;
const int MAX_DATA = conn->db->MAX_DATA;
int i = 0;
// I want to allocate memory for the rows and the strings here...
// Clearly the freads are failing, how would I actually allocate properly?
for(i = 0; i < MAX_ROWS; i++) {
rc = fread(conn->db->rows, sizeof(struct Address),
1 , conn->file);
if(rc != 1) die("Failed to load rows.", conn);
rc = fread(&conn->db->rows[i], sizeof(char),
MAX_DATA, conn->file);
if(rc != MAX_DATA) die("Failed to load characters.", conn);
}
以下补充资料:
涉及的结构:
struct Address {
int id;
int set;
char *name;
char *email;
};
struct Database {
int MAX_DATA;
int MAX_ROWS;
struct Address *rows;
};
struct Connection {
FILE *file;
struct Database *db;
};
创建数据库:
void Database_create(struct Connection *conn, const int MAX_ROWS, const int MAX_DATA)
{
int i = 0;
conn->db->MAX_ROWS = MAX_ROWS;
conn->db->MAX_DATA = MAX_DATA;
conn->db->rows = (struct Address *)malloc(sizeof(struct Address)*MAX_ROWS);
for(i = 0; i < MAX_ROWS; i++) {
struct Address addr;
addr.id = i;
addr.set = 0;
addr.name = (char *)malloc(sizeof(char)*MAX_DATA);
addr.email = (char *) malloc(sizeof(char)*MAX_DATA);
conn->db->rows[i] = addr;
}
}
最后,清理:
void Database_close(struct Connection *conn)
{
int i = 0;
struct Address *cur_row = NULL;
if(conn) {
if(conn->file) fclose(conn->file);
if(conn->db) {
if(conn->db->rows) {
for(i = 0; i < conn->db->MAX_ROWS; i++) {
cur_row = &conn->db->rows[i];
if(cur_row) {
free(cur_row->name);
free(cur_row->email);
}
}
free(conn->db->rows);
}
free(conn->db);
}
free(conn);
}
}
答案 0 :(得分:1)
您知道必须根据您的评论为rows
分配。所以你可以这样做:
conn->db->rows = malloc(MAX_ROWS * sizeof(struct Address));
然后,在您阅读row
之后,您需要在读取数据之前为每个row
的数据分配内存。
for (i = 0; i < ROWS; ++i) {
rc = fread(&conn->db->rows[i], sizeof(struct Address),
1 , conn->file);
if(rc != 1) die("Failed to load rows.", conn);
conn->db->rows[i].name = malloc(MAX_DATA);
conn->db->rows[i].email = malloc(MAX_DATA);
rc = fread(&conn->db->rows[i]->name, sizeof(char),
MAX_DATA, conn->file);
if(rc != MAX_DATA) die("Failed to load name.", conn);
rc = fread(&conn->db->rows[i]->email, sizeof(char),
MAX_DATA, conn->file);
if(rc != MAX_DATA) die("Failed to load email.", conn);
}
您必须确保以与创建数据库时写出的顺序相同的顺序读取数据。
答案 1 :(得分:0)
fread
仅处理连续的内存,因此您一次只能读取一个结构或数组。您的字符串与Address结构不相邻。你可以解决这两种方式:
1)fread
初始结构,然后fread
分别为每个字符串。然后使用指向字符串的指针更新结构。 (如果你想要高效,你必须写下字符串大小,这样你就可以存储字符串的'有效'部分而不是max-size字符串。)
2)你可以通过将它们声明为固定大小的数组(而不是指向数组的指针)来使字符串成为结构的一部分。
struct Address {
int id;
int set;
char name[MAX];
char email[MAX];
};