'fread'动态分配的结构

时间:2013-06-20 21:32:09

标签: c pointers struct

因此,我目前正致力于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);
     }

}

2 个答案:

答案 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];
};