先上一段測試程式:
char *aa() {
char *p = malloc(10); // 動態分配,"hello" 存於" 堆"(heap)
p[0] = 'h';
p[1] = 'e';
p[2] = 'l';
p[3] = 'l';
p[4] = 'o';
p[5] = '/0';
printf("sub aa pointer: %p/n", p);
printf("sub aa content: %s/n", p);
return p;
}
char *bb() {
char p[] = "hello"; // 自動分配,"hello" 存於棧(stack)
printf("sub bb pointer: %p/n", p);
printf("sub bb content: %s/n", p);
return p; //warning , bb() 函數完後,p 所指地區被釋放
}
char *cc() {
char *p = "hello"; //"hello" 存於常量區(static)
printf("sub cc pointer: %p/n", p);
printf("sub cc content: %s/n", p);
return p;
}
int main()
{
char *raa = aa();
printf("main aa pointer: %p/n", raa);
printf("main aa content: %s/n/n", raa);
char *rbb = bb();
printf("main bb pointer: %p/n", rbb);
printf("main bb content: %s/n/n", rbb);
char *rcc = cc();
printf("main cc pointer: %p/n", rcc);
printf("main cc content: %s/n/n", rcc);
free(rbb);
return 0;
}
程式解析:
1. aa() 中,雖然p 是局部變數,儲存在棧中,但它指向的是堆記憶體,函數跳出後堆記憶體不會自動被釋放,所以main() 函數中可以接收的到。
2. bb() 中,p 是一個數組,一個局部變數,屬於自動分配。函數在跳出後,返回的是p 的內容(數組的地址),但數組本身已經被釋放了,所以在主函數中接收不到p 數組的內容。
3. cc() 中,雖然p 是局部變數,儲存在棧中,但它指向的“hello ”是常量,屬於靜態分配,儲存在靜態儲存區,函數跳出時常量也不會被釋放,釋放的只是p 變數,它存的只是“hello ”的地址,但它已經返回給main() 函數接收了,它釋放了沒關係,所以main() 函數同樣可以接收“hello ”。
記憶體配置方式有三種:靜態分配、動態分配、自動分配。
1. 靜態分配:編譯時間完成的;儲存在靜態儲存區,程式結束時才被釋放,例如全域變數,static 變數,代碼,常量等(代碼、常量可以單獨歸類)。
2. 動態分配:程式在啟動並執行時候用malloc 或new 申請的任意多少的記憶體,程式員自己負責在何時用free 或delete 釋放記憶體;儲存在堆裡( 不是資料結構的堆) 。
3. 自動分配:函數執行時由系統自動建立,函數結束時自動被釋放;儲存在棧裡,例如函數的局部變數。棧記憶體配置運算內建於處理器的指令集中,效率很高,但是分配的記憶體容量有限。
堆的解釋:系統把連續閒置堆記憶體看成一個個的塊,再用指標鏈表把所有的塊串起來,需要分配時遍曆鏈表,找出一個足夠大小的塊進行分配,剩下的把它放到鏈表中;用完釋放時,系統再把它放回鏈表中。
PS: 有趣的比喻:可以把堆記憶體看成一個沙堆(我忘了在哪本書上看到的了),需要時,用鏟子在沙堆裡剷出一些沙,用完時,在把它放回到沙堆裡,所以,兩次取沙子不太可能會取到同樣的。
轉自:http://blog.csdn.net/diamont1001/article/details/6123184