c 中函式呼叫涉及到變數的記憶體分配問題

2022-08-22 10:12:07 字數 926 閱讀 3801

理解區域性變數和全域性變數的記憶體問題核心是理解編譯器在主函式和子函式呼叫執行過程中是如何管理分配記憶體的。

記憶體中資料區被分為動態資料區與靜態資料區。其中靜態資料區可以簡單理解為寫在main函式與其他函式外部的全域性變數儲存的區域,程式執行時,編譯器為其在這個區域內分配記憶體,其生命週期貫穿整個程式執行過程。

這裡我們主要講講動態資料區,動態資料區中主要分為heap與stack。假設下圖為記憶體區域,其中的堆區和棧區分別具有基位址;堆區和棧區的記憶體分配都是先從基位址開始分配,並在記憶體釋放後指標再次回到基位址。這裡紅色邊框區域為堆區,藍色為棧區;其中主函式中的變數在堆區分配,而主函式中呼叫的函式內部的區域性變數在棧區分配,其生命週期為整個子函式呼叫期。以下面最簡單的小程式的執行為例:

堆基位址

(棧基位址) 

void f(int c)

int main()

首先程式從主函式開始執行,執行語句int a;int b;此時編譯器在堆區依次為其分配記憶體。

b=2堆基  a=1fe

棧基  c

當第一次呼叫子函式f時, c,e,f依次進棧(圖中省略了棧頂指標);

d=3b=2

堆基  a=1

棧基   

此時棧區為空,當再次執行子函式f時,如同第一次一樣,編譯器再次在棧區為其變數分配記憶體,從而區域性變數進棧。f呼叫結束,棧區記憶體釋放。在遞迴演算法的執行過程中,函式不斷呼叫自身,編譯器為每個子函式開闢棧區空間,其實現類似於此。當主函式結束後,堆區的記憶體才被釋放。

大多數時候,編譯器在編譯時在記憶體中做了很多任務作,我們不能從**本身了解記憶體分配,例如理解 i++ 語句與i=i+1的區別,乍一看一樣,無非是給i 加1,但記憶體中卻有本質的區別,i=i+1 執行過程中,編譯器首先會將i+1的值儲存在乙個臨時變數中,這個臨時變數編譯器自動申請,然後再把這個臨時變數賦值給i , 而i++則直接給i加1; 

JavaScript中涉及到的RegExp型別

正規表示式 由一些普通字元和特殊字元組成的,用以描述一種特定的字元規則的表示式,它是用來限制使用者在網際網路中輸入的規則 建立正規表示式 var 變數名 正規表示式的內容 修飾符 var reg 123456789 i var 變數名 new regexp 正規表示式的內容,修飾符 var reg ...

讀取網頁中涉及到的高度

目前已經總結的有 offsetheight offsettop clientheight clienttop scrollheight scrolltop innerheight outerheight將來準備看的有 有關控制滾動的該屬性是乙個唯讀屬性,返回乙個代表畫素高度的整數值,高度包括元素高度...

GPU設計中涉及到的座標

在gpu硬體處理以及opengl建模過程中都將設計到6種空間處理,直接構成了6種座標處理的環境 1 model space或者object space 這個空間是物件空間,與其他空間沒有關係,只是直接形成這個物體的具體輪廓以及其他屬性 attribute 物件的最終構成都是有vertex都成,由他的...