1. 程式人生 > >realloc可能導致的記憶體洩露

realloc可能導致的記憶體洩露

在良好的程式碼風格中,其中有一項要求就是,一個函式只做一件事情。如果該函式實現了多個功能,那基本上可以說這不是一個設計良好的函式。 今天看C庫中的函式realloc。其原型是void *realloc(void *ptr, size_t size);函式說明如下: realloc() changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged to the minimum of the old and new sizes; newly allocated memory will be uninitialized. If ptr is NULL, the call is equivalent to malloc(size); if sizeis equal to zero, the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
總結一下,有以下幾種行為: 1. 與名字相符,真正的realloc,引數ptr和size均不為NULL,重新調整記憶體大小,並將新的記憶體指標返回,並保證最小的size的內容不變; 2. 引數ptr為NULL,但size不為0,那麼行為就等於malloc(size); 3. 引數size為0,則realloc的行為為free(ptr);這時原有的指標已經被free掉,不能繼續使用。而此時realloc的返回值為NULL。這意味著不檢查realloc的返回值,直接使用,會導致crash。

看,一個簡單C庫函式,卻賦予了三種行為,所以這個realloc並不是設計良好的庫函式。估計也是為了相容性,才容忍這個函式一直在C庫中。雖然在編碼中,realloc會提供一定的方便,但是也很容易引發bug。

下面就舉兩個例子,來說明一下。 1. realloc第一種行為引發的bug
  1. void *ptr = realloc(ptr, new_size);
  2. if (!ptr) {
  3.     錯誤處理
  4. }
這裡就引出了一個記憶體洩露的問題,當realloc分配失敗的時候,會返回NULL。但是引數中的ptr的記憶體是沒有被釋放的。如果直接將realloc的返回值賦給ptr。那麼當申請記憶體失敗時,就會造成ptr原來指向的記憶體丟失,造成洩露。 正確的處理應該是這樣
  1. void *new_ptr = realloc(ptr, new_size);
  2. if (!new_ptr) {
  3.     錯誤處理。
  4. }
  5. ptr =
     new_ptr
2. 第三種行為引發的bug 這種bug由一種不好的程式設計習慣引發的。即認為申請記憶體始終可以成功,因此並不檢查malloc的返回值。這在一般情況下,不會引發問題。但是對於realloc來說,當new_size為0時,realloc返回NULL。而在後面的程式碼上,繼續使用new_ptr,比如會導致程式crash。
  1. void *new_ptr = realloc(old_ptr, new_size);
 //其它程式碼  ...... ...... 從上面可以看出,在面對這個設計並非良好的API時,我們需要小心小心再小心。上面只是舉了兩個例子,其實還有一些其它的小問題。