malloc和free在教材裡不知講了多少,今天實際用到一處,就出問題了。
案發現場是我用VC++在WINXP下編程,先看這一段代碼
{
BYTE *pBuffer;
pBuffer = (BYTE *)malloc(64);
pBuffer = pBuffer + 32;
free(pBuffer);
pBuffer = NULL;
} //第一段
先聲明一個指標,然後分配64位元組給它。操作指標向後移動32位元組,最後把這個指標free掉並設為NULL。這樣雖然操作時的資料還留在記憶體地區裡,但已經沒有指標指向該地區,資料可以被後面的程式覆蓋了。看起來沒錯吧?恩恩好象是沒錯, 抓了三個同事來問,全票通過. 但在實際上呢, 運行時會跳出這個警告:
而如果把代碼改成
{
BYTE *pBuffer;
pBuffer = (BYTE *)malloc(64);
pBuffer = pBuffer + 32;
pBuffer = pBuffer -32;
free(pBuffer);
pBuffer = NULL;
} //第二段代碼
就沒錯了。李博士的解釋是:malloc的時候系統建立了一個鏈表之類的東西,裡麵包含了起始地址和長度;而free的時候根據參數中的指標進行判斷,如果該指標符合鏈表中某一節的起始地址,那麼就把這一節free掉,如果去free一個不在鏈表中的地址,就出錯啦。
比較好的處理方式是這樣
{
BYTE *pBuffer;
BYTE *pBytePtr;
pBuffer = (BYTE *)malloc(64);
pBytePtr = pBuffer;
pBytePtr = pBytePtr + 32;
free(pBuffer);
pBuffer = NULL;
pBytePtr = NULL;
} //第三段代碼
即保留malloc時候的初始地址,然後賦給另外一個臨時指標。操作時使用後者。free的時候把保留的起始指標free掉,而臨時指標只是個變數,置空就可以了。
文章到這裡似乎就應該寫完了,不過由於johnathan的幫忙, 突然有了下文。
注意警告框中的_CrtIsValidHeapPointer,在MSDN上查到這個函數的說明為:
Verifies that a specified pointer is in the local heap (debug version only).
int _CrtIsValidHeapPointer(const void *userData);
Parameter:
userData Pointer to the beginning of an allocated memory block.
Return Value:
_CrtIsValidHeapPointer returns TRUE if the specified pointer is in the local heap. Otherwise, the function returns FALSE.
也就是說僅在debug版本中檢查free參數是否為the beginning of an allocated memroy block.
那麼就編譯一個release版本,果然,運行通過, 沒彈出什麼警告或錯誤。但運行通過不等於正常無誤, 博士認為這就是無聲無息導致記憶體泄露的罪魁禍首. 即使release版裡面也應該free起始地址.
那麼結論就是:free掉非malloc起始地址的指標,在debug版本中會出錯警告,而在release版本中不會彈出警告但仍然是有錯的。所以,還是推薦使用第三段代碼的用法