2012-01-17 45 views
0

我是C新手,在C決定釋放一個對象時以及它決定保留一個對象時並沒有真正掌握它。如何防止c中的懸掛指針/垃圾?

heap_t是指向結構堆的指針。

heap_t create_heap(){ 
    heap_t h_t = (heap_t)malloc(sizeof(heap)); 
    h_t->it = 0; 
    h_t->len = 10; 
    h_t->arr = (token_t)calloc(10, sizeof(token)); 
    //call below a couple of times to fill up arr 
    app_heap(h_t, ENUM, "enum", 1); 
    return h_t; 
} 

把h_t通過

int app_heap(heap_t h, enum symbol s, char* word, int line){ 
    int it = h->it; 
    int len = h->len; 

    if (it + 1 < len){ 
     token temp; 
     h->arr[it] = temp; 
     h->arr[it].sym = s; 
     h->arr[it].word = word; 
     h->arr[it].line = line; 
     h->it = it + 1; 
     printf(h->arr[it].word); 
     return 1; 
    } else { 
     h->len = len*2; 
     h->arr = realloc(h->arr, len*2); 
     return app_heap(h, s, word, line); 
    } 

} 

爲什麼我h_t->改編與垃圾填滿,最終我得到一個分段錯誤?我該如何解決?任何C編碼技巧/風格,以避免這樣的東西?

+0

什麼是「標記」?對於它的價值,我不認爲你需要聲明令牌溫度並將其分配給h-> arr [it]。鑑於h-> arr是一個標記指針,並且您有它的內存,h-> arr [it]已經是一個標記結構。 – 2012-01-17 14:25:15

+0

當你說「填滿垃圾」時,你怎麼知道這一點?有什麼症狀? – 2012-01-17 14:27:21

回答

1

首先,要回答你有關崩潰的問題,我想你得到段錯誤的原因是,你無法通過sizeof(token)在調用realloc繁殖len。您最終會寫入已分配塊的末尾,最終會觸發段錯誤。至於「決定釋放一個對象和何時保留一個對象」,C並沒有爲你決定它:只要你通過調用free來告訴它,沒有問你任何進一步的問題。這種「服從」有時會讓你付出代價,因爲你可能會意外地釋放你仍然需要的東西。將空指針清空是一個好主意,可以更快地解決問題(不幸的是,由於共享指針,這不足以完全消除問題)。

free(h->arr); 
h -> arr = NULL; // Doing this is a good practice 

總而言之,在C中管理內存是一項繁瑣的工作,需要大量的思考和紀律。您需要檢查每個分配調用的結果以查看它是否失敗,並在執行時執行許多輔助任務。

+0

thx thx thx thx thx – Derek 2012-01-17 15:01:56

1

如果你已經自己分配了一些東西,並且明確地調用了例如「 malloc(),它將保持分配狀態,直到您free()它(或直到程序終止,通常)。

我想這:

token temp; 
    h->arr[it] = temp; 
    h->arr[it].sym = s; 
    /* more accesses */ 

很奇怪,前兩行沒有做任何明智的。

正如dasblinkenlight所指出的那樣,您無法將重新分配到字節中,這會導致陣列在嘗試增長時顯着收縮,並且完全損壞它。

  • 你不應該投的返回值的malloc()realloc(),在C.
  • 記住realloc()可能會失敗,在這種情況下,你會失去你的指針,如果你覆蓋像你一樣。
  • 代碼中有大量的重複,即realloc(h->arr, len*2)而不是realloc(h->arr, h->len * sizeof *h->arr)等等。

請注意上一個項目符號點是否也修復了上述realloc()縮放錯誤。

+0

不要忘記用2乘以實際增長數組。 – 2012-01-17 14:57:50

0

你不重新分配到合適的大小,realloc的聲明必須是:

realloc(h->arr, sizeof(token) * len*2); 
        ^^^^^^^^^^^^ 

(或者也許更好realloc(h->arr, sizeof *h->arr * h->h_len);

在C語言中,你有責任來釋放你分配的內存。你必須釋放()你已經使用malloc/calloc/realloc的內存。 C運行時永遠不會釋放任何東西,除非程序終止(一些更深奧的系統可能不會釋放內存)。

此外,儘量保持一致,一般的分配形式始終爲T *foo = malloc(sizeof *foo),並且不要複製東西。

例如

 
h_t->arr = (token_t)calloc(10, sizeof(token)); 
      ^^^^^^^^  ^^ ^^^^^^^^^^^^^ 
  1. 不要投的malloc在C.返回值這是unncessesary,如果你忘了包括stdlib.h中
  2. 中投token_t但可能的sizeof隱藏嚴重的編譯器警告和錯誤適用於令牌,爲什麼它們不同,並且它們與* h_t-> arr是同一類型?
  3. 你已經有神奇的10值,使用h_t-> len個
  4. 如果你改變的類型h_t->改編,你必須記住要改變的sizeof(..)

所以使創建用C懸擺指針這個

h_t->arr = calloc(h_t->len, sizeof *h_t->arr); 
0

兩個主要問題是不釋放其分配的內存,並共享指針後分配 NULL的指針。

第一個問題的解決方案是自動將指針歸零。

void SaferFree(void *AFree[]) 
{ 
    free(AFree[0]); 
    AFree[0] = NULL; 
} 

來電者,而不是調用

free(p); 

將調用

SaferFree(&p); 

在對於第二,更難被siolved問題: The rule of three說:

如果你需要明確地聲明析構函數,複製構造函數或複製賦值運算符,您可能需要明確聲明它們全部三個。

在C中共享指針只是簡單地複製它(複製指定)。這意味着在C編程時使用三條規則(或一般規則爲0) 時,要求程序員提供一種方法來構造和特別地破壞這樣的分配,這是可能的,但不是簡單的任務,特別是當C不提供如C++中隱式激活的描述符。