C/C++ free(NULL)的思考

最近code review的時候發現了一段magic code,free的指針指向了NULL,當時膽戰心驚,第一反應就是free一個空指針會引起NE,應該和double free一個地址是同樣的效果。但是冷靜下來,想到這段代碼是一段老code了,而且還在一直運行,應該沒有問題纔對,不然的話早就暴露出來了。

查到C標準庫free有下面的描述。

**Description
The C library function void free(void ptr) deallocates the memory previously allocated by a call to calloc, malloc, or realloc.
Declaration
Following is the declaration for free() function.
void free(void ptr)
Parameters
ptr —— This is the pointer to a memory block previously allocated with malloc, calloc or realloc to be deallocated. If a null pointer is passed as argument, no action occurs.
Return Value
This function does not return any value.

如果free一個空指針,是沒有任何事情發生的。和double free一個指針是不一樣的。所以在申明一個指針的時候,最好賦初值NULL,例如char* str = NULL,後面不小心free了也沒有問題發生。free一塊malloc的指針後,需要將指針置爲NULL,可以避免double free。原先以爲free一塊malloc的指針後將指針置爲NULL是編碼規則要求的,但是現在看是有着實際意義的。
現在維護的code中含有大量的下面類似的code。其實這種寫法也不能避免double free,因爲free之後沒有將指針置爲NULL。

if (pointer != NULL) {
    free(pointer);
}

下面寫法會更好

if (pointer != NULL) {
    free(pointer);
    pointer = NULL;
}

但是每次free之前還是都要判斷pointer是否爲NULL,感覺也不是很好,如果大家都養成free之後將pointer置爲NULL並且聲明定義指針賦初值NULL的習慣,那麼判斷條件是可以remove掉的。

{
    free(pointer);
    pointer = NULL;
}

下面寫一個sample供大家參考。

typedef struct {
    int id;
    cahr* str;
} TestParam;

void testFree(int id) {
    TestParam *testParam = NULL;
    testParam = (TestParam*)malloc(sizeof(TestParam));
    if (testParam == NULL) {
        return;
    }
    memeset(testParam, 0, sizeof(TestParam));
    testParam->id = id;
    testParam->str = NULL;
    // testParam->str 可能會在函數中某些地方通過malloc的方式賦值,也可能不會。
    // 無論testParam->str是否通過malloc賦過值,都可以直接使用free函數,因爲testParam->str初始值爲NULL。當然條件是前面沒有出現過free之後沒有賦NULL的邏輯。
    free(testParam->str);
    testParam->str = NULL;
    free(testParam);
    testParam = NULL;
}

因爲一個項目不會是一個人開發,知識準備可能不一樣,我們只能嚴格要求自己了。free的時候需要判斷是否是NULL,free之後置NULL。申明指針時初始值設爲NULL。
所以最後一段code,一般會寫成:

if(testParam != NULL) {
    if (testParam->str != NULL) {
        free(testParam->str);
        testParam->str = NULL;
    }
    free(testParam);
    testParam = NULL;
}

另外free的指針只限於malloc, calloc or realloc這三個分配後的內存指針。如果自己定義了一個局部指針
char str[] = “abcdef”;
如果free(str),我推測應該什麼都不會做纔對(undefined behavior occurs),和free(NULL)一樣,大家可以做一下試驗,畢竟結構和malloc的結構不一樣,當然也要避免這種情況的發生。
free一塊malloc的內存後,這塊內存就是未知的,可能保持原來的值,也可能已經被分配了,這時候再次free就會導致嚴重問題了(undefined behavior occurs)。

編程真是學無止境,只能靠一點一點積累和保持一顆好奇和學習的心了。越是認爲簡單的東西,包含的知識越是豐富。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章