1.問題
在LeetCode上做題偶然發現一道題:free內存後,還繼續調用該指針,於是好奇,想了解free到底做了什麼。
這段代碼的free()掉了nextTemp結點的malloc內存,但後面還可以使用nextTemp = nextTemp->next。
2.原因
2.1 free的實現原理
操作系統在調用malloc函數時,會默認在malloc分配的物理內存前面分配一個數據結構,這個數據結構記錄了這次分配內存的大小,在用戶眼中這個操作是透明的。
那麼當用戶需要free時,free函數會把指針退回到這個結構體中,找到該內存的大小,這樣就可以正確的釋放內存了。
使用Linux的man手冊查看(#man 3 free),只是說分配了之後需要free,並沒有過多的說明:
The free() function frees the memory space pointed to by ptr,
which must have been returned by a previous call to malloc(), calloc(), or realloc().
Otherwise, or if free(ptr) has already been called before,
undefined behavior occurs.
If ptr is NULL, no operation is performed.
2.2 回答
找了一些資料,發現的確是可以的,並且編譯也不會報錯,具體原因如下:
1)free只是釋放了malloc所申請的內存,並沒有改變指針的值;
2)由於指針所指向的內存空間已經被釋放,所以其他代碼有機會改寫其中的內容,相當於該指針從此指向了自己無法控制的區域(無法控制這麼說還是可以去使用的,只是危險),也成爲野指針(野指針指指向一個已刪除的對象或未申請訪問受限內存區域的指針。與空指針不同,野指針無法通過簡單地判斷是否爲NULL避免)。
3)爲了避免錯誤,所以最好在free之後,使指針指向NULL。
根據原理的解釋分析:free函數的作用只是告訴操作系統該內存不用了,可以收回,操作系統就把該內存鏈接到鏈接表上,
但是這段內存用戶還是可以訪問到的,只是該內存的值可能已經發生了變化。
3.總結
其實,free函數只是將參數指針指向的內存歸還給操作系統,並不會把參數指針置NULL,爲了以後訪問到被操作系統重新分配後的錯誤數據,所以在調用free之後,通常需要手動將指針置NULL。從另一個角度來看,內存這種底層資源都是由操作系統來管理的,而不是編譯器,編譯器只是向操作系統提出申請。所以free函數是沒有能力去真正的free內存的。只是告訴操作系統它歸還了內存,然後操作系統就可以修改內存分配表,以供下次分配。
4.案列
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *str = (char *)malloc(100);
if(NULL == str)
{
printf("malloc failed !\n");
return 1;
}
sprintf(str,"hello world");
if(str != NULL) {
printf("%p,%s\n", str,str);
}
free(str);
if(str != NULL) {
printf("%p,%s\n", str,str);
}
str = NULL;
printf("%p,%s\n", str,str);//這裏把它指向NULL
/* 這裏驗證str爲NULL時,free多次都是沒有問題的,但不爲NULL,則不行 */
free(str);
free(str);
return 0;
}
結果輸出: