C程式記憶體的分配,const ,volatile,static

audience_fzn發表於2018-08-03

一個c/c++程式佔用的記憶體分別位以下幾個部分

1.棧區:由編譯器自動分配釋放,儲存為函式而分配的區域性變數,函式引數,返回資料,返回地址等,其操作方式類似於資料結構裡的棧

2.堆區:一般由程式設計師手動分配釋放,若程式設計師不釋放程式結束時可能由OS回收。

3.全域性區(靜態區):由於存放全域性變數,靜態變數常量,程式結束後由系統釋放

4.常量區:用於儲存常量字串

5程式碼區:用於存放函式體(類成員函式和全域性函式)的二進位制程式碼

這並不是真正的實體地址,一個計算機中可以有多個程式在執行,而每一個程式都有一個執行時堆疊,而實體記憶體只有一個,這只是一個虛擬地址

記憶體分配的三種方式:

1.從靜態區分配:記憶體在程式編譯的時候就已經分配好了,這塊記憶體在程式的整個執行期間都存在,例如:全域性變數,static變數

2.在棧上分配:效率高,但是棧的空間有限,執行時建立,執行結束後系統自動釋放。棧時向下生長的,先定義的變數地址高,後定義的變數地址低,但是在棧上定義的陣列的地址是由低向高的,因為陣列一次性開闢一整塊空間,然後分配給陣列內的元素。

3.在堆上分配:也稱為動態記憶體分配,堆是自下向上生長的,變數的地址一次增大。用malloc()或new()申請任意空間,程式設計師自己負責在何時用free()/delete()釋放記憶體。動態記憶體的生命週期由程式設計師自己負責,使用非常靈活。但是一定要記得回收,不然可能會產生記憶體洩漏的問題。頻繁分配、釋放不同大小的空間還有可能導致記憶體碎片的問題。

 

const、volatile關鍵字

const:修飾變數,使變數具有常性。編譯器會在編譯時進行優化,將const變數放入暫存器

#include<stdio.h>
int main()
{
    const int num = 10;
    int *p = (int*)&num;
    *p = 20;
    printf("%d",num);
    return 0; 
}

//輸出仍然為10 ,為什麼呢?

編譯器在編譯期間會對程式碼進行優化,當編譯器看到num被const修飾時,就會將num的值放在暫存器中(以提高訪問的效率),以後只要使用num就會區暫存器裡面取,所以即使改變了num對應的記憶體中的值,暫存器也感知不到,所以就會輸出10。

但我們對程式碼做如下修改:

#include<stdio.h>
int main()
{
    volatile const num = 10;
    int *p = (int*)&num;
    *p = 20;
    printf("%d",num);
    return 0;
}

//這樣對*p做修改時num就等於20,為什麼呢?

volatile:保證記憶體的可見性,使編譯器在編譯時不進行優化,執行時不快取,每次都去記憶體中讀出。

 

static:

  • 修飾函式:改變其連結屬性,由外部連結屬性-->內部連結屬性(函式只能在當前原始檔內使用,不能在其他原始檔內使用),儲存型別(生命週期)和作用域不受影響
  • 修飾變數:

          1)全域性變數:與修飾函式的作用一致,改變其連結屬性(外->內),儲存型別和作用域不受影響

          2)區域性變數:改變其生命週期(儲存型別),由自動變數變成了靜態變數,作用域和連結屬性不受影響

 

 

 

 

 

 

相關文章