2013-06-20 62 views
2

所以我目前正在Learn C the Hard Way和粘貼在課外鍛鍊17「fread'ing一個動態分配的結構

只需要什麼是固定大小的數據庫從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); 
    } 

} 

回答

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

您必須確保按照創建數據庫時寫出的順序讀取數據。

+0

哦!我實際上並沒有對conn-> db之外的任何東西進行fwrite()。有時間解決這個問題,看看它能做些什麼。 –

+0

一旦我得到了fwrite的工作,並重寫了我所有的函數(malloc需要一個新的地址結構),一切都奏效了。謝謝您的幫助。 –

+0

@MicaiahChang:非常歡迎。 – jxh

0

fread只處理連續內存,所以一次只能讀取一個結構或數組。您的字符串不與您的地址結構連續。您可以通過以下兩種方式解決:

1)fread初始結構體,然後fread每個字符串分開。然後用指向字符串的指針更新結構。 (如果你想提高效率,你必須把字符串大小寫下來,這樣你就可以存儲字符串的「有效」部分而不是最大字符串。)

2)你可以使通過將它們聲明爲固定大小的數組(而不是指向數組的指針)來構造該結構的一部分。

struct Address { 
int id; 
int set; 
char name[MAX]; 
char email[MAX]; 
}; 
+0

這正是他想要避免的。 – Kyle