程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++中不同變量、函數在內存中的內存情況《轉》,變量《轉》

C++中不同變量、函數在內存中的內存情況《轉》,變量《轉》

編輯:C++入門知識

C++中不同變量、函數在內存中的內存情況《轉》,變量《轉》


一、一個C++編譯的程序占用的內存分為以下幾個部分

1、棧區:由編譯器自動分配 存放函數的參數值,局部變量的值等,操作方式類似於數據結構中的棧。

2、堆區:一般由程序員分配釋放,若程序員不釋放,程序結束時 可能 有系統收回。它與數據結構中的堆是兩回事。分配方式類似於鏈表。

3、全局區(靜態區):全局變量和靜態變量是存儲放在一塊的,初始化的全局變量和靜態變量在一個區域,未初始化的在相鄰的另一個區域。

     程序結束後由系統釋放。

4、文字常量區:常量字符串就存放在這裡。程序結束後有系統自動釋放。

5、程序代碼區:存放函數體的二進制代碼。

 

二、堆棧的理論知識

1、申請方式

棧:有系統自動分配。例如定義局部變量int i  = 0;函數傳參時使用值傳遞。

堆:需要程序員自己申請並指明大小。如用malloc函數和new運算符。

2、申請後的系統響應

棧:只要棧的剩余空間大於所申請的空間,系統將為程序提供內存,負責報告棧溢出異常。

堆:這個設計到系統的內存管理,操作系統有一個記錄空閒內存地址的鏈表,然後根據系統的內存分配策略分配內存。

3、申請大小的限制 

棧:在windows下,棧是向低地址擴展的數據結構,是一塊連續的內存區域。也就是說棧底和棧頂的地址和最大容量是

       系統預先規定好的。在windows下據說是棧大小是2M,如果申請的空間超過棧的剩余空間時將提示溢出。因此棧的

      空間較小。

堆:堆是向高地址擴展的數據結構,是不連續的內存區。因為系統用鏈表來存儲空閒內存的地址的,而鏈表遍歷的方向

       是從低地址到高地址。堆的大小受限於計算機系統中有效地虛擬內存。獲得的空間比較靈活也比較大。

4、效率方面

堆:速度比較慢,容易產生碎片,不過用起來方便。在windows最快的是利用VirtualAlloc分配內存,他不在堆也不在棧中,

      而是直接在棧的地址空間中保留一塊內存。使用起來速度快,靈活。

棧:速度快,不過由系統自動分配和控制。

5、存放內容方面

堆:一般是在堆的頭部用一個字節放堆的大小。堆中具體內容有程序員安排。

棧:在函數調用時第一個進棧的是主函數中下一條指令(函數執行語句的下一條可執行語句)地址,然後是各個函數的參數,

       大多數C/C++編譯器中,函數參數是從右往左入棧,然後是函數中的局部變量。注意:靜態變量不如棧的。本次函數調

       用結束後,局部變量先出棧,然後是函數參數,最後棧頂指針指向最開始存的主函數中下一條指令地址,程序由該點繼

       續運行。

 

三、實例解說

//全局初始化區
int i1 = 0;
int i2 = 0;
int i3 = 0;

//全局初始化區
static int i4 = 0;
static int i5 = 0;
static int i6 = 0;

//全局未初始化區
int i7;
int i8;
int i9;


void Creat()
{
    cout<<"Creat"<<endl;
}

void Add()
{
    cout<<"Add"<<endl;
}

void Delete()
{
    cout<<"Delete"<<endl;
}

int Max(int a,int b)//在調用此函數時參數從右往左開始壓棧
{
    return a>b?a:b;
}

int _tmain(int argc, _TCHAR* argv[])
{    
    cout<<"打印全局初始化區變量i1-i3的地址:"<<endl;
    cout<<&i1<<" "<<&i2<<" "<<&i3<<endl;

    cout<<"打印全局初始化區靜態變量i4-i6的地址:"<<endl;
    cout<<&i4<<" "<<&i5<<" "<<&i6<<endl;

    cout<<"打印全局未初始化區變量i7-i9的地址:"<<endl;
    cout<<&i7<<" "<<&i8<<" "<<&i9<<endl;

    cout<<"依次打印上面三個函數Creat、Add、Delete地址:"<<endl;
    cout<<&Creat<<endl;
    cout<<&Add<<endl;
    cout<<&Delete<<endl;

    //棧區
    int c1 = 'a';
    int c2 = 'b';
    int c3;
    int c4;

    cout<<"打印主函數內局部變量c1-c4地址,其中c3,c4未初始化"<<endl;
    cout<<&c1<<"  "<<&c2<<"  "<<&c3<<"  "<<&c4<<"  "<<endl;

    char *pStr1 = "12345";//12345在常量區,pStr在棧上
    char *pStr2 = "1122";

    void *p = pStr1;
    void *q = pStr2;
    cout<<"打印常量地址"<<endl;
    cout<<p<<endl;
    cout<<q<<endl;

    static int i10 = 0;//全局(靜態)初始化區
    cout<<"在局部函數中定義靜態變量地址,請於上面答應的其他全局區地址作比較"<<endl;
    cout<<&i10<<endl;

    int *p1 = new int;//堆區
    int *p2 = new int;//堆區
    cout<<"打印堆區地址"<<endl;
    cout<<p1<<endl;
    cout<<p2<<endl;

    strcpy(pStr1,"1144");//12345在常量區,編譯器可能將pStr1文字常量1144優化成一個地方
   

    getchar();
    return 0;
}

輸出:

image

以上結果在VS2008中測試。對上面結果地址觀察發現,全局未初始化區的變量是按從高到低地址按申明定義的

順序壓棧,變量i7緊鄰全局初始化段的第一個變量i1.而全局初始化段的變量(包括靜態,不做區分的)從低地址

到高地址按申明的順序壓棧(不是指上面所指的棧區,請區別開來,這是就地址變化過程而言的,你會看到它與

局部函數變量起始地址完全不同)。函數在程序代碼段中地址是按申明順序遞增的。函數局部變量在棧去是按照

申明順序從高到低的地址進棧的。這裡看到我定義的幾個int變量地址相差是12個字節還不清楚是不是編譯器原因。

常量的開始地址來看跟全局變量應該屬於一個區。堆區的地址開頭也是另外一個段。

補充一點:數組變量內部元素是按照元素下標從低地址到高地址壓棧的。

一般局部變量一般是從高低地址到低地址壓棧的。

從上面結果來看全局變量實際可能在堆區。

 

以上內容主要參考http://blog.csdn.net/benny5609/article/details/2217258原創文章

生命在於折騰,生活就是如此的豐富多彩

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved