1. 程式人生 > 其它 >C++核心程式設計 1 程式的記憶體模型

C++核心程式設計 1 程式的記憶體模型

1、記憶體分割槽模型

C++程式在執行時,將記憶體大方向劃分為4個區域

  程式碼區:存放函式體的二進位制程式碼,由作業系統進行管理(寫的所有程式碼都在程式碼區)

  全域性區:存放全域性變數、靜態變數以及常量

  棧 區:由編譯器自動分配釋放,存放函式的引數值,區域性變數等

  堆 區:由程式設計師分配和釋放,若程式設計師不釋放,程式結束時由作業系統回收

  記憶體四區的意義:不同區域的資料,賦予不同的生命週期,給我們更大的靈活程式設計

程式執行前:

  在程式編譯後,生成了exe可執行程式,未執行該程式前分為兩個區域

程式碼區:

    存放CPU執行的機器指令

    程式碼區是共享的,共享的目的是對於頻繁被執行的程式,只需要在記憶體中有一份程式碼即可

    程式碼區是隻讀的,使其只讀的原因是防止程式意外地修改了它的指令  

全域性區:

    全域性變數(main函式外面)和靜態變數(在普通變數前加static)存放於此

    全域性區還包含了常量區,字串常量 ("hello world") 和其他常量(const修飾的全域性變數)也存放於此

    該區域的資料在程式結束後由作業系統釋放

  總結:

    C++中在程式執行前分為全域性區和程式碼區

    程式碼區特點是共享和只讀

    全域性區中存放全域性變數、靜態變數、常量

    常量區中存放const修飾的全域性變數和字串常量

程式執行後:

棧 區:

    由編譯器自動分配釋放,存放函式的引數值,區域性變數等

    注意:不要返回區域性變數的地址,棧區開闢的資料由編譯器自動釋放

#include<iostream>
using namespace std;

//棧區資料注意事項  ---  不要返回區域性變數的地址
//棧區的資料由編譯器管理開闢和釋放

int * func(int b)   //形引數據也會放在棧區
{
   b = 100;
   cout << b << endl;
int a = 10; //區域性變數 存放棧區,棧區的資料在函式執行完後自動釋放 return &a; //返回區域性變數的地址 } int main() {
//接收函式的返回值 int * p = func(1); cout << *p << endl; //第一次可以打印出正確的資料 10 ,是因為編譯器防止使用者是誤操作而做了一次保留 cout << *p << endl; //第二次這個資料就不再保留 打印出來的是亂碼 因為區域性變數a的記憶體已經被釋放 system("pause"); return 0; }

    打印出來的結果:

堆 區:

    由程式設計師分配釋放,若程式設計師不釋放,程式結束時由作業系統回收

    在C++中主要利用new在堆區開闢記憶體 

    例項: 

#include<iostream>
using namespace std;

int * func()
{
    //利用new關鍵字  可以將資料開闢到堆區
   //指標 本質也是區域性變數,放在棧上。指標儲存的資料是放在堆區
int * p = new int (10); return p; } int main() { int * p = func(); //接收函式的返回值 cout << *p << endl; cout << *p << endl; system("pause"); return 0; }

    列印結果:

new操作符

  C++中利用new操作符在堆區開闢資料

  堆區開闢的資料,由程式設計師手動開闢,手動釋放,釋放操作符delete

  語法:new資料型別

  利用new建立的資料,會返回該資料對應的型別的指標

  例項:1、基本語法

#include<iostream>
using namespace std;

int * func()
{
    //在堆區建立整型資料
    //new返回的是 該資料型別的指標
    int * p = new int (10);    
    return p;     
}

void test1()  //new的基本語法
{
    int * p = func();
    cout << *p << endl;
    cout << *p << endl;
    cout << *p << endl;
    //堆區資料由程式設計師管理開闢、釋放,若想釋放 利用關鍵字delete
    delete p;
    cout << *p << endl;  //記憶體已經被釋放,再次訪問就是非法操作,會報錯
}
int main()
{
    //int * p = func();  //接收函式的返回值
    test1();
    
    system("pause");
    return 0;
}

列印結果:因為deletep 後,p已被釋放,故第四次打印出錯。

    2、在堆區new陣列

#include<iostream>
using namespace std;


//2、在堆區利用new開闢陣列
void test2()
{
    //建立10個 整型資料的陣列,在堆區
    int * arr = new int[10];  //10代表陣列有10個元素
    for (int i = 0; i < 10; i++)
    {
        arr[i] = i + 100;  //給10個元素賦值  100~109
    }
    for (int i = 0; i < 10; i++)
    {
        cout << arr[i] << endl;
    }
    //釋放堆區陣列
    //釋放陣列的時候要加[]才可以
    delete[] arr;
}
int main()
{
    test2();
    system("pause");
    return 0;
}

    列印結果: