2013-11-22 40 views
0

最近我遇到了內存釋放問題。首先,打擊是C代碼:malloc和free的內存操作到底做了什麼?

#include <stdio.h> 
#include <stdlib.h> 
int main() 
{ 
     int *p =(int*) malloc(5*sizeof (int)); 

     int i ; 
     for(i =0;i<5; i++) 
      p[i ]=i; 
     p[i ]=i; 
     for(i =0;i<6; i++) 
      printf("[%p]:%d\n" ,p+ i,p [i]); 
     free(p); 
     printf("The memory has been released.\n"); 
} 

顯然,有內存超出範圍的問題。當我使用VS2008編譯器,它給下面的輸出和有關內存釋放一些錯誤:

[00453E80]:0 
[00453E84]:1 
[00453E88]:2 
[00453E8C]:3 
[00453E90]:4 
[00453E94]:5 

然而,當我使用的cygwin的GCC 4.7.3編譯器,我得到下面的輸出:

[0x80028258]:0 
[0x8002825c]:1 
[0x80028260]:2 
[0x80028264]:3 
[0x80028268]:4 
[0x8002826c]:51 
The memory has been released. 

顯然,代碼運行正常,但5沒有寫入內存。 因此,VS2008和gcc在處理這些問題上可能存在一些差異。 你們能給我一些關於這方面的專業解釋嗎?提前致謝。

+6

您爲5個項目分配空間,但是索引超過了分配量的末尾。這是未定義的行爲,任何事情都可能發生。 –

+2

你正在超越第二個for循環的分配範圍。 p [5]就是當時內存中的任何值。 – NmdMystery

+0

Woops,我沒有看到額外的p [i] = i,這意味着最後的值應該是5.不知道gcc在那裏做什麼。 – NmdMystery

回答

1

沒有確定性的「解釋」。將數據寫入超出分配的內存限制的未知區域導致未定義的行爲。行爲是不可預測的。這裏的所有都是它的。

雖然看到51打印出來仍然很奇怪。通常,GCC還將打印5,但會因內存損壞消息free而失敗。您如何設法使此代碼打印51並不完全清楚。我強烈懷疑你發佈的代碼不是你運行的代碼。

+0

這裏的代碼正是我所跑的。我知道指數超出範圍。我想知道爲什麼代碼被免費粉碎。免費如何知道要發佈的內存大小是多少? – xkfz007

+0

'malloc'節省了多少內存分配在一個特定的地址,所以免費'可以釋放相同的數量。 'malloc'如何保存該值以及對分配塊周圍的腐敗檢查是特定於實現的。 –

+0

我的同事給了我一些解釋,VS2008會檢查內存中的值是否有效,以決定它將釋放的內存大小。 – xkfz007

1

這是很正常的,因爲您從未將任何數據分配到p [5]的mem空間中。該程序將打印出該數據存儲在該空間中的數據。

0

看來你有多個問題,所以,讓我嘗試單獨回答:

  1. 正如所指出的其他上面,你寫過去的數組的末尾這樣,一旦你做了那麼,你處於「未定義行爲」領域,這意味着可能發生任何事情,包括打印5,6或0xdeadbeaf,或炸燬你的電腦。

  2. 在第一種情況下(VS2008),空閒似乎報告標準輸出上的錯誤消息。這對我來說並不明顯,這個錯誤信息是什麼,所以很難解釋發生了什麼,但你稍後會在評論中問VS2008如何知道你釋放的內存大小。通常,如果分配內存並將其存儲在指針p中,則大量內存分配器(malloc/free實現)將以分配的內存大小存儲在p [-1]處。在實踐中,通常也在地址p [p [-1]]處存儲一個特殊值(比如0xdeadbeaf)。這個「canary」會被免費檢查,看看你是否寫過數組的末尾。總而言之,你的5 * sizeof(int)數組可能至少是5 * sizeof(int)+ 2 * sizeof(char *)個字節,而用VS2008編譯的代碼使用的內存分配器有很多內建的檢查。

  3. 在海灣合作委員會的情況下,我發現它令人驚訝,你得到51打印。如果你想仔細研究wwhy,我建議獲取生成代碼的asm轉儲,並在調試器下運行它以檢查5是否真的寫在數組的末尾(gcc可能已經決定不生成該代碼是因爲它是「未定義的」),如果是這樣,則在該內存位置放置一個觀察點以查看誰覆蓋它,何時以及爲什麼。

+0

感謝您的詳細回覆。我更瞭解內存分配。 – xkfz007