(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的數目。)
請刪除所有的混亂,只留下必要的信息。 「你能幫忙嗎?」是你的問題嗎? – qrdl
對於初學者來說,'pool-> cells = realloc(pool-> cells,...)'''realloc'使用非常糟糕。 – netcoder
@netcoder當realloc()返回NULL時,你指的是內存泄漏。 「非常」有點強。如果意圖是在realloc()失敗時立即終止,這種情況並不是很糟糕,在這種情況下,泄漏只是在程序退出的時候。 –