在子函式中malloc分配記憶體和free釋放記憶體的方法(基於C)
阿新 • • 發佈:2019-01-07
1. 子函式malloc分配記憶體
為了增強程式可讀性,有時會在子函式中malloc分配記憶體。測試瞭如下三種方法,容易想到的是第一種。事實證明這種也是錯誤的!
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct _dataStc { int buf[100]; int size; }dataStc; void func1(dataStc* p) { p = (dataStc*)malloc(sizeof(dataStc)); p->size = 10; return; } dataStc* func2(void) { dataStc* p; p = (dataStc*)malloc(sizeof(dataStc)); p->size = 10; return p; } void func3(dataStc** p) { *p = (dataStc*)malloc(sizeof(dataStc)); (*p)->size = 10; return; } int main(int argc, const char * argv[]) { dataStc *p1 = NULL; dataStc *p2 = NULL; dataStc *p3 = NULL; func1(p1); p2 = func2(); func3(&p3); if (p1 == NULL) { printf("p1=NULL\n"); } else { printf("p1->size:%d\n", p1->size); } if (p2 == NULL) { printf("p2=NULL\n"); } else { printf("p2->size:%d\n", p2->size); } if (p3 == NULL) { printf("p3=NULL\n"); } else { printf("p3->size:%d\n", p3->size); } return 0; }
執行結果如下所示:
p1=NULL
p2->size:10
p3->size:10
結論:只有後兩種方法能正確分配記憶體。即直接返回記憶體指標,或將二級指標作為引數傳入子函式。這是因為,在子函式中,記憶體指標只是被當做一個變數來處理的(雖然這個變數被定義為dataStc *),對其賦值後再返回,它的值當然沒改變。
另外,由於成員選擇運算子“->”的優先順序比取值運算子“*”高,所以在func3中,*p需要加括號。
2. 子函式free釋放記憶體
在子函式中釋放記憶體,很容易想到的是寫個下面這樣的函式釋放記憶體:
void func_free(dataStc* p) { free(p); return; }
上面的函式能釋放記憶體,但也有個缺陷。因為C在free一段記憶體後,該記憶體的確是被釋放了(可以被其他程式使用),但指標p仍然指向該段記憶體(而不是我們期待的NULL)。這時p就成為野指標了(不同於空指標),仍然可以訪問或修改p指向的記憶體。如果其他程式不慎又通過p訪問了記憶體,程式或許不報錯,但可能帶來不可預知的後果。
因此,保險做法是,在free後,將p賦為NULL。由於這裡又將輸入變數p修改了,因此仍然需要傳遞二級指標。正確的程式碼為:
void func_free(dataStc** p)
{
free(*p);
*p = NULL;
return;
}
這樣,在其他程式中訪問p時,就可先判斷其是否為NULL了。