2012-12-14 35 views
0

(C)realloc的陣列修改數據通過項目(C)realloc的陣列修改由項目數據_pointed_

你好指出

一個不錯的奇怪的錯誤我覺得分享;-)需要一些初步的解釋:

首先,我有一個字符串類型PString它們的大小(和一個哈希值),後面跟着一個靈活的數組成員與字節。下面是類型和種類構造函數(末尾的printfl語句調試):

typedef struct { 
    size_t size; 
    uint  hash; 
    char  bytes[]; 
} PString; 

// offset from start of pstring struct to start of data bytes: 
static const size_t PSTRING_OFFSET = sizeof(size_t) + sizeof(uint); 

PString * pstring_struct (string str, size_t size, uint hash) { 
    // memory zone 
    char *mem = malloc(PSTRING_OFFSET + size * sizeof(char)); 
    check_mem(mem); 

    // string data bytes: 
    memcpy(mem + PSTRING_OFFSET, str, size); 
    mem[PSTRING_OFFSET + size] = NUL; 

    // pstring struct: 
    PString * pstr = (PString *) mem; 
    pstr->size = size; 
    pstr->hash = hash; 

    printfl("*** str:'%s' (%u) --> pstr:'%s' (%u) 0x%X", 
    str, size, pstr->bytes, pstr->size, pstr); /////////////////////// 
    return pstr; 
} 

[這一工程歡迎任何評論:我不知道在所有做正確的事情,在這裏。這是我第一次使用靈活的數組成員,我無法找到分配結構使用它們的exemples]

其次,那些pstrings存儲在一個字符串池,這意味着作爲哈希表實施了一套。像往常一樣,衝突的「桶」(以散列&爲模)是單元格的簡單鏈接列表,每個單元格都包含一個pstring 指針和指向下一個單元格的指針。唯一特別的細節是單元本身存儲在一個數組中,而不是分配到堆中的任何位置[1]。希望畫面清晰。這裏是Cell定義:

typedef struct SCell { 
    PString  * pstr; 
    struct SCell * next; 
} Cell; 

似乎都做工精細,包括池本身的測試電池。現在,當測試一個pstring例程(搜索)時,我注意到一個字符串發生了變化。經過一番研究後,我終於猜測這個問題與池的增長有關,並最終可以在細胞陣列的增長周圍減少問題(因此,在將單元格重新分配到列表之前)。下面是圍繞這個不斷增長的調試打印的線條,與show_pool程序產生輸出(只顯示字符串)複印件,及輸出本身:

static void pool_grow (StringPool * pool, uint n_new) { 
    ... 
    // Grow arrays: 
    show_pool(pool); ///////////////////// 
    pool->cells = realloc(pool->cells, pool->n_cells * sizeof(Cell)); 
    check_mem(pool->cells); 
    show_pool(pool); //////////////////// 
    ... 

static void show_pool (StringPool * pool) { 
    if (pool->n == 0) { 
     printfl("{}"); 
     return; 
    } 

    printf("pool   : {\"%s\"", pool->cells[0].pstr->bytes); 

    PString * pstr; 
    uint i; 
    for (i = 1; i < pool->n; i++) { 
     pstr = pool->cells[i].pstr; 
     printf(", \"%s\"", pstr->bytes); 
    } 

    printl("}"); 
} 

// output: 
pool   : {"", "abc", "b", "abcXXXabcXXX"} 
pool   : {"", "abc", "b", "abcXXXabcXXXI"} 

正如你所看到的,所存儲的最後一個字符串有一個額外的字節'我'。由於在此期間我只是打電話給realloc,我發現自己有點被阻止進一步調試;努力思考並不能幫助揭示這個謎團。 (請注意,單元格只保存pstring 指針,那麼如何才能增加單元格數組來改變字符串字節呢?)另外,我被這個事實嚇倒了,在神祕的'I'之後似乎有一個相當方便的NUL,因爲printf停在那裏。

謝謝。 你能幫忙嗎?

[1]沒有什麼特別的理由在這裏做一個字符串池。我通常這樣做是爲了免費獲得一個有序集或地圖,另外還有參考的地點。 (唯一的開銷是單元陣列必須除了桶的陣列生長,但人們可以通過predimensioning減少growings的數目。)

+1

請刪除所有的混亂,只留下必要的信息。 「你能幫忙嗎?」是你的問題嗎? – qrdl

+0

對於初學者來說,'pool-> cells = realloc(pool-> cells,...)'''realloc'使用非常糟糕。 – netcoder

+0

@netcoder當realloc()返回NULL時,你指的是內存泄漏。 「非常」有點強。如果意圖是在realloc()失敗時立即終止,這種情況並不是很糟糕,在這種情況下,泄漏只是在程序退出的時候。 –

回答

2

由於size不包括空終止,

mem[PSTRING_OFFSET + size] = NUL; 

無效。每一個其他問題都源於此。

+0

就是這樣,謝謝ecatmur!我重寫了一些代碼來清理,顯然太早了,並且錯過了+1 ... –