C 堆疊與函式呼叫

2022-08-16 09:57:11 字數 2139 閱讀 5933

一、c++程式記憶體分配

1)在棧上建立。在執行函式時,函式內區域性變數的儲存單元都在棧上建立,函式結束是,這些儲存單元自動被釋放。棧記憶體的分配運算內置於處理器的指令集中,一般採用暫存器來訪問,效率很高但是分配的記憶體容量有限。

2)從堆上分配,亦稱動態記憶體分配。程式在執行時malloc或new任意多的記憶體,程式設計師自己負責在何時用free和delete來釋放記憶體。動態記憶體的生存週期由程式設計師自己決定,使用非常靈活。

3)從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在,例如全域性變數,static變數。靜態儲存區在堆內。

4)文字常量分配在文字常量區,程式結束後由系統釋放。文字常量在堆內。

5)程式**區,在堆內。

下面舉個例子:

1 #include

2 #include3

int a=0; //

全域性初始化區

4char *p1; //

全域性未初始化區

5int

main()

6

二、三種記憶體物件的比較

棧物件的優勢是在適當的時間自動生成,又在適當的時間自動銷毀,不需要程式設計師操心;而棧物件的建立速度一般較堆物件快,因為分配堆物件時,會呼叫operate new操作,operate new操作會採用某種記憶體空間搜尋演算法,而這個搜尋過程可能是很浪費時間的,產生棧物件沒有這麼麻煩,它僅僅需要移動棧頂指標就行了。但是,要注意的是,通常棧空間容量比較小,一般是1mb~2mb(在windows中為2mb),所以體積比較大的物件不適合在棧中分配。特別要注意在遞迴函式中最好不要使用棧物件,因為隨著遞迴呼叫深度的增加,所需要的棧空間也會線性增加,當所需棧空間不夠時,便會導致棧溢位,這樣就會產生執行時錯誤。

堆物件建立和銷毀都要程式設計師負責,所以,如果處理不好,就會發生記憶體問題。如果分配了堆物件卻忘記了釋放就會產生記憶體洩露;如果已經釋放了物件,卻沒有將相應的指標置為null,該指標就是所謂的「懸掛指標」,再度呼叫此指標就會出現非法訪問,嚴重時導致程式崩潰。但是高效地使用堆物件也可以大大提高**質量。比如我們需要建立乙個大物件,且需要被多個函式訪問,那麼這個時候建立乙個堆物件無疑是良好的選擇,因為我們通過在各個函式之間傳遞這個堆物件的指標,便可以實現對該物件的共享,相比整個物件的傳遞,大大降低了物件的拷貝時間。另外,相比於棧空間,堆的容量要大的多,甚至在物理記憶體不夠時,如果這時還需要建立新的堆物件,通常不會產生執行是錯誤,而是系統會使用虛擬記憶體來擴充套件實際的物理記憶體。

靜態儲存區。所有的全域性物件、靜態物件都在靜態儲存區分配。全域性物件時在main()函式執行之前就分配好了的。其實,在main函式的顯示**之前,會呼叫乙個由編譯器生成的_main()函式,而_main()函式會進行所有全域性物件的構造和初始化工作。而在main()函式結束之前,會呼叫由編譯器生成的exit函式,來釋放所有的全域性物件。

比如下面的**:

void main()

//顯式**

實際上被轉化成這樣

void main()

_main();  //隱式**,由編譯器產生,用於構造所有全域性物件

...   ...;   //顯式**

exit();    //隱式**,由編譯器產生,用於釋放所有全域性物件

三、棧記憶體與堆記憶體的區別

1)申請後系統的響應

棧:只要棧的剩餘空間大於所申請的空間,系統將為程式提供記憶體,否則將報異常提示棧溢位,windows中將提示overflow。

堆:在記錄空閒記憶體位址的鍊錶中尋找乙個空間大於所申請空間的堆結點,然後將該結點從空閒結點鍊錶中刪除,並將該結點的空間分配給程式。另外,對於大多數系統會在這塊記憶體空間的首位址出記錄本次分配空間的大小,這樣**中的delete 才能正確釋放本記憶體空間。系統會將多餘的那部分重新放回到空閒鍊錶中。

2)棧和堆的儲存內容

棧:在棧中,第乙個進棧的是進入主函式後下一條指令(函式呼叫語句的下一條可執行語句)的位址,然後是函式的各個引數,在大多數編譯器中,引數是由右往左入棧,然後是函式中的區域性變數。注意,靜態變數不入棧。出棧則剛好順序相反。當本次函式呼叫結束後,區域性變數先出棧,然後是引數,最後棧頂指標指向最開始存的位址,也就是主函式中的下一條指令,程式由該點繼續執行。

堆:一般在堆的頭部用乙個位元組存放堆的大小,具體內容由程式設計師安排。

c 函式堆疊呼叫

由乙個.cpp c檔案到達乙個可執行檔案分為以下幾部分 預編譯階段 進行巨集替換,刪除注釋,展開標頭檔案,新增行號等 編譯階段 進行詞法,語法,語義分析,和 優化,生成彙編指令 彙編 翻譯指令 連線階段 合併段和符號表,符號解析 執行階段 建立虛擬位址和物理對映,載入指令和資料,程式入口位址寫入暫存...

函式呼叫堆疊

一 函式呼叫堆疊 認真體會每一行指令位址!include intsum int a,int b mov ebp,esp 讓esp回退到ebp的位置,回退棧幀的過程中,沒有對棧幀中的值進行清0的操作 pop ebp 出棧並把出棧的值賦給ebp int main 下圖為上面示例函式,程式在sum函式中,...

函式呼叫堆疊

一 棧 1 傳統的棧 被定義為乙個特殊的容器,使用者可以將資料壓入棧中,也可以將壓入 棧中的資料彈出,但必須遵守一條規則 先進後出。2 計算機系統中的棧 是乙個有以上屬性的動態記憶體區域,壓棧操作使得棧增大,彈出操作使棧減小。棧通常是向下增長的。3 最重要的是棧儲存了乙個函式呼叫所需的維護資訊,這通...