2010-10-05 179 views
1

我在C中寫入一個函數,它接受一個鏈表和一個謂詞,並返回一個包含滿足此條件的鏈表的所有值的數組。這裏的功能:C Realloc錯誤 - 「Assertion`ptr == alloc_last_block'失敗!」

void **get_all_that(list_t *l, int (*pred)(const void *)) { 
    void **vals = NULL; 
    int i = 0; // Number of matches found 
    const size_t vps = sizeof(void *); 
    node_t *n = l->first; 
    while (n) { 
     if (pred(n->value)) { 
      vals = (void **)realloc(vals, i*vps); // (*) 
      vals[i] = n->value; 
      i++; 
     } 
     n = n->next; 
    } 
    if (vals != NULL) { 
     vals = (void **)realloc(vals, i*vps); 
     vals[i] = NULL; // NULL-terminate array 
    } 
    return vals; 
} 

我在於始終返回1的謂詞傳遞(即get_all_that基本上to_array),以及我的迭代,其中i = 4得到一個錯誤的加星號的線。回溯錯誤(從SIGABRT自動打印)是「*** glibc detected ***〜/ list/test:realloc():invalid next size:0x0804c0e8 ***」

我打開了GDB在i = 4時調用realloc之前告訴它打破。然後我嘗試從GDB手動調用realloc(vals,i * vps),並得到錯誤消息:「由ld.so檢測到的不一致:dl-minimal.c:138:realloc:聲明`ptr == alloc_last_block'失敗! 」

任何人都知道發生了什麼事?

回答

2

您的realloc正在分配一個元素太少。嘗試用i+1代替i。在更換傳遞給它的指針之前,您還應該檢查realloc的失敗,否則在失敗時將會發生內存泄漏(更不用說崩潰,因爲您未能檢查NULL),並從中刪除不必要和醜陋的轉換返回值realloc也不錯。

+0

這樣做。接得好。爲什麼這些演員陣容無效? – Nick 2010-10-05 03:26:31

+0

@Nick:因爲'void *'隱式轉換爲任何其他指針類型(在C中;而不是在C++中)。 – caf 2010-10-05 03:52:02

+1

無效指針('malloc'和'realloc'返回)的整點是它們自動轉換爲任何(非函數)指針類型。爲什麼這是一個糟糕的主意(在風格,可維護性和掩蓋錯誤方面)是一個您可以搜索的主題。 – 2010-10-05 03:53:58

0

而你的第一個realloc稱爲長度爲0,這是一個free。所以建議把i+1加倍重要。

+0

這本身並不是一個問題,因爲下一次調用會將由0調用返回的指針再次傳遞給'realloc'到'realloc'。無論大小爲0的realloc是否返回NULL指針或有效的唯一指針(標準允許),程序將按預期工作。 – 2010-10-05 17:07:29

+0

還應該注意的是,GNU'malloc'在零尺寸分配時返回一個唯一的非空指針的行爲使得它很難找到該錯誤,並且改變了本來很容易被捕獲的空指針 - 將segfault解引用爲一個輕度難以發現的內存腐敗錯誤。 – 2010-10-05 17:08:43