變數在記憶體的位置

2022-05-16 03:44:16 字數 4416 閱讀 4465

1、首先,講下 「堆 heap」 和 「棧 stack」 的區別:

乙個由 c/c++編譯過的程式占用的記憶體分為一下幾個部分

(1)、棧區 stack:由編譯器自動分配釋放,存放函式的引數值,區域性變數的值等。這個棧的操作方式類似於資料結構中的棧。

(2)、堆區 heap:一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os**,注意它與資料結構中的堆是兩回事,分配方式類似於鍊錶。

(3)、*全域性區(靜態區)static*** : 全域性變數和靜態變數的儲存是放在一塊的。初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數和靜態變數又放在相鄰的另一塊區域中。程式結束後由系統釋放。

(4)、*文字常量區*: 常量字串放在這裡。程式結束後由系統釋放。

(5)、程式**區: 存放函式體的2進製**。

根據變數的位置可以分為全域性變數和區域性變數

根據變數的靜態屬性可以分為靜態變數和非靜態變數。

根據變數的const屬性可以分為const變數和非const變數。

針對上面的幾種變數分類,變數的初始化分為以下幾種:

全域性變數和區域性變數的不同主要體現在變數的作用範圍上,全域性變數的初始化分為兩種,非類物件的變數的初始話發生在函式的編譯階段,如果我們沒有顯示的初始化,編譯器會預設初始化,類型別的全域性變數的初始化發生在程式執行階段的main函式之前。對於區域性變數,不會執行預設初始化,因此在使用區域性變數之前必須先進行變數的初始化。

靜態變數和非靜態變數的初始化:

靜態變數的分類:靜態變數根據其位置可以分為三種:全域性靜態變數、定義在函式中的靜態變數以及定義在類中的靜態變數。

靜態變數的初始化:編譯器要求不同,有的要求必須主動完成初始化,有的編譯器會完成預設初始化,但是值不確定。所以,在使用靜態變數的時候,我們一般要求必須在定義的同時完成初始化。對於g++編譯器,如果靜態變數是全域性或者函式的區域性變數,都會完成預設初始化。但是如果類包含靜態資料成員,c++要求這個靜態資料成員僅可以在類內部完成宣告,然後在類外,且任何函式之外,完成靜態成員的初始化,初始化可以賦初始值,也可以不賦值,不賦值會預設初始化。

初始化的形式如下:

int a::i = 1;

如果試圖在類內初始化,編譯器會報錯:iso c++ forbids in-class initialization of non-const static member 『a::k』 。

如果在函式內(比如main函式)試圖初始化, 編譯器同樣會報錯:qualified-id in declaration before 『=』 token

如果不初始化直接使用,由於未分配記憶體,還是會報錯:undefined reference to `a::k』

報錯願意分析: 由於類的靜態資料成員所有類共有,所以,類在分配記憶體的時候並不會主動分配這個靜態資料成員的記憶體,因此要求我們必須主動要求分配記憶體。必須在類外完成初始化的原因是因為,這個靜態資料成員儲存在資料段(全域性區),如果在函式內初始化,意味著要求編譯器在棧區委這個變數分配記憶體,這也是錯誤的。

但是這中情況有乙個例外,那就是如果類的靜態資料成員是const, 那麼 這個變數必須在類內完成初始化。

對於全域性變數,如果程式僅由乙個原始檔構成,那麼全域性靜態變數類同於全域性變數,在編輯階段進行初始化。如果程式由多個原始檔構成,那麼全域性靜態變數僅對所在的原始檔有效,而全域性變數在整個程式中有效。

定義在函式中的靜態變數:定義在函式中的靜態變數的作用是變數值的保持,對於初始化而言,函式中的靜態變數僅在定義時進行初始化,且在整個程式的執行中,函式中的靜態變數只初始化一次。

類中的靜態成員變數:類的靜態成員存在於任何物件之外,物件中不包含任何與靜態資料成員有關的資料,因此,靜態資料成員不是由建構函式進行初始化的,類的靜態資料成員的初始化過程必須在類的定義之外,相對的,類的非靜態資料的初始化發生在類的建構函式中。

const物件和非const物件的初始化:

const物件必須在定義的時候進行初始化,引用的本質是乙個const指標,因此引用也必須在定義的時候進行初始化。

各種變數的儲存位置:

常規的變數(非全域性,非靜態)儲存在棧上。

動態資料等顯示分配的內存在堆上。

全域性變數和靜態變數儲存在資料段(全域性區)

const全域性變數存放於唯讀資料段,在第一次使用時為其分配記憶體。

2、例子程式 :  這是乙個前輩寫的,非常詳細

int a = 0; 全域性初始化區 

char *p1; 全域性未初始化區

main()

記憶體分配區域

32位作業系統下為:1g核心態,3g使用者態

bss段 :通常是指用來存放程式中 未初始化的全域性變數、靜態變數(全域性變數未初始化時預設為0)的一塊記憶體區域

資料段 :通常是指用來存放程式中 初始化後的全域性變數和靜態變數

**段 :通常是指用來存放程式中 **和常量

堆 :通常是指用來存放程式中 程序執行時被動態分配的記憶體段 ( 動態分配:malloc / new,者動態釋放:free / delete)

棧 :通常是指用來存放程式中 使用者臨時建立的區域性變數、函式形參、陣列(區域性變數未初始化則預設為垃圾值)也就是說我們函式括弧「{}」中定義的變數(但不包括static宣告的變數,static意味著在資料段中存放變數)。除 以外,在函式被呼叫時,其引數也會被壓入發起呼叫的程序棧中,並且待到呼叫結束後,函式的返回值也會被存放回棧中。由於棧的先進後出特點,所以棧特別方便用來儲存/恢復呼叫現場。從這個意義上講,我們可以把堆疊看成乙個寄存、交換臨時資料的記憶體區。它是由作業系統分配的,記憶體的申請與**都由os管理。

堆(heap)和棧(stack)的區別

1、申請方式

棧: 由系統自動分配。例如,宣告在函式中乙個區域性變數int b;系統自動在棧中為b開闢空間

堆: 需要程式設計師自己申請,並指明大小( 動態分配:malloc / new,者動態釋放:free / delete)

2、申請後系統的響應

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

堆:首先應該知道作業系統有乙個記錄空閒記憶體位址的鍊錶,當系統收到程式的申請時,

會遍歷該鍊錶,尋找第乙個空間大於所申請空間的堆結點,然後將該結點從空閒結點鍊錶中刪除,並將該結點的空間分配給程式,另外,對於大多數系統,會在這塊記憶體空間中的首位址處記錄本次分配的大小,這樣,**中的delete語句才能正確的釋放本記憶體空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒鍊錶中。

3、申請大小的限制

棧:在windows下,棧是向低位址擴充套件的資料結構,是一塊連續的記憶體的區域。這句話的意思是棧頂的位址和棧的最大容量是系統預先規定好的,在windows下,棧的大小是2m(也有的說是1m,總之是乙個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。

堆:堆是向高位址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用鍊錶來儲存的空閒記憶體位址的,自然是不連

續的,而鍊錶的遍歷方向是由低位址向高位址。堆的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。

(4)申請效率的比較:

棧:由系統自動分配,速度較快。但程式設計師是無法控制的。

堆:是由new分配的記憶體,一般速度比較慢,而且容易產生記憶體碎片,不過用起來最方便.

另外,在windows下,最好的方式是用virtual alloc分配記憶體,他不是在堆,也不是在棧,而是直接在程序的位址空間中保留一塊記憶體,雖然用起來最不方便。但是速度快,也最靈活。

(5)堆和棧中的儲存內容

棧:在函式呼叫時,第乙個進棧的是主函式中後的下一條指令(函式呼叫語句的下一條可執行語句)的位址,然後是函式的各個引數,在大多數的c編譯器中,引數是由右往左入棧的,然後是函式中的區域性變數。注意靜態變數是不入棧的。

當本次函式呼叫結束後,區域性變數先出棧,然後是引數,最後棧頂指標指向最開始存的位址,也就是主函式中的下一條指令,程式由該點繼續執行。

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

(6)訪問效率的比較

bss段的大小記錄在**?-》 關於bss段的大小

bss段的大小,記錄在段表裡,記錄的是所有未初始化變數總共的大小,bss段只在段表裡有個記錄,但實際並不存在這個段.,每個未初始化的變數的大小放在了符號表裡。

更詳盡的例子:

#include using namespace std;

int a = 0;//初始化的全域性變數:儲存在資料段

char *p1;//未初始化的全域性變數:儲存在bss段

int main()

c/c++中 變數的儲存位置、c語言中區域性變數和全域性變數_等在記憶體中的存放位置

關於c++中的各種變數以及儲存位置總結

各變數在記憶體中的位置

在linux中寫乙個程式,裡面全域性變數,區域性變數,static,const,常數,陣列,輸出這些變數的位址 包括賦值的和沒有賦值的,各類資料型別 include int a int b 1 int const c 2 static int d static int e 3 char src1 2...

變數和值在記憶體中的儲存位置

變數和值在記憶體中的儲存位置 一 預備知識 程式的記憶體分配 乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯器自動分配釋放 存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。2 堆區 heap 一般由程式設計師分配釋放,若程式設計師不釋放,程式結...

變數和值在記憶體中的儲存位置

一 預備知識 程式的記憶體分配 乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯器自動分配釋放 存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。2 堆區 heap 一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os 注意它與資料結...