C C 語言程式的儲存區域

2021-07-02 14:05:07 字數 4699 閱讀 8454



問題提出:

看輸出結果,使用c1、c2、c3輸出字串都相同,但c1、c2、c3本身的內容不相同。9620588 1899312看出,完全是兩塊地方,推斷9620588屬於常量區,1899312屬於棧區。1899324 1899312 1899300這三個數可以看出指標區域為棧區。

#include

"stdafx.h"

#include

#include

using

namespace

std;

int_tmain

(int

argc

, _tchar

* argv)

c3 = 

"abc"

;    

// abc\0在常量區,賦值將會把字串"abc"首位址給c3,改變了c3的位址,如果使用使用free(c3)會報錯

printf(

"%d %d %s\n"

, &c1, c1, c1);

printf(

"%d %d %s\n"

, &c2, c2, c2);

printf(

"%d %d %s\n"

, &c3, c3, c3);

//free(c3);

getchar();

return0;

}執行結果:

程式的記憶體分配

c語言**(文字檔案)形成可執行程式(二進位制檔案),需要經過編譯-彙編-鏈結三個階段。編譯過程把c語言文字檔案生成匯程式設計序,彙編過程把匯程式設計序形成二進位制機器**,鏈結過程則將各個原始檔生成的二進位制機器**檔案組合成乙個檔案。

c語言編寫的程式經過編譯-彙編-鏈結後,將形成乙個統一檔案,它由幾個部分組成。在程式執行時又會產生其他幾個部分,各個部分代表了不同的儲存區域: 1、

**段(code或text)

**段由程式中執行的機器**組成。在c語言中,程式語句進行編譯後,形成機器**。在執行程式的過程中,cpu的程式計數器指向**段的每一條機器**,並由處理器依次執行。 2、

唯讀資料段(ro data)

唯讀資料段是程式使用的一些不會被更改的資料,使用這些資料的方式類似查表示式的操作,由於這些變數不需要更改,因此只需要放置在唯讀儲存器中即可。 3、

已初始化讀寫資料段(rw data)

已初始化資料是在程式中宣告,並且具有初值的變數,這些變數需要占用儲存器的空間,在程式執行時它們需要位於可讀寫的記憶體區域內,並具有初值,以供程式執行時讀寫。 4、

未初始化資料段(bbs)

未初始化資料是在程式中宣告,但是沒有初始化的變數,這些變數在程式執行之前不需要占用儲存器的空間。 5、

堆(heap)

堆記憶體只在程式執行時出現,一般由程式設計師分配和釋放,在具有作業系統的情況下,如果程式沒有釋放,作業系統可能在程式(例如乙個程序)結束後**記憶體。 6、

棧(stack)

棧記憶體只在程式執行是出現,在函式內部使用的變數、函式的引數以及返回值將使用棧空間,棧空間由編譯器自動分配和釋放。

例項:

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

static int b = 20;   //全域性初始化區         data段

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

const int a = 10;    //                     ro data段

void main()

二、堆和棧的理論知識 1、

申請方式

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

堆(heap):需要程式設計師自己申請,並指明大小,在c中使用malloc函式申請記憶體。例如:p1=(char*)malloc(10);在c++中用new運算子,如int *p2=new int;但是注意p1、p2本身是在棧中的,而p1、p2所指向的內容在堆中。(

malloc和new開闢的記憶體區,用free和delete釋放時,要注意確保釋放的記憶體和分配的記憶體是同一塊記憶體區,例如:問題提出例項中如果使用free(c3)釋放記憶體會報錯。)

2、申請後系統的響應

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

堆:首先應該知道作業系統有乙個記錄空閒記憶體位址的鍊錶,當系統收到程式的申請時,會遍歷該鍊錶,尋找第乙個空間大雨所申請空間的堆結點,然後將該結點從空閒中的首位址處記錄本次分配的大小,這樣,**中的delete(或free)語句才能正確的釋放本記憶體空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒鍊錶中。 3、

申請大小的限制

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

堆:堆是向高位址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用鍊錶來儲存空閒記憶體位址的,自然是不連續的,而鍊錶的遍歷方向是由低位址向高位址。堆的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。 4、

申請效率的比較

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

堆:是由new分配的記憶體,一般速度比較慢,而且容易產生記憶體碎片,不過用起來最方便。(另外,在windows下,最好的方式是使用virtualalloc分配記憶體,他不是在堆,也不是在棧,而是直接在程序的位址空間中保留一塊記憶體,雖然用起來最不方便。但是速度最快,也最靈活。) 5、

堆和棧中的儲存內容

棧:在函式呼叫時,第乙個進棧的是主函式中後的下一條指令(函式呼叫語句的下一條可執行語句)的位址,然後是函式的各個引數,在大多數的c編譯器中,引數是由右往左入棧的,然後是函式中的區域性變數。注意靜態變數是不入棧的。當本次函式呼叫結束後,區域性變數先出棧,然後是引數,最後棧頂指標指向最開始存的位址,也就是主函式中的下一條指令,程式由該點繼續執行。

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

訪問效率的比較

char

s1 = 

"aaaaaaaaaaaaaaa";

char

*s2 = 

"bbbbbbbbbbbbbbb";

aaaaaaaaaaaaaaa是在執行時刻賦值的,而bbbbbbbbbbbbbbb是在編譯時就確定的。但是,在以後的訪問中,在棧上的陣列比指標所指向的字串(例如堆)快。

比如:void

main()

對應的反彙編**:

a = c[1];

011f5317  mov         eax,1  

011f531c  shl         eax,0  

011f531f  mov         cl,byte ptr c[eax]  

011f5323  mov         byte ptr [a],cl  

a = p[1];

011f5326  mov         eax,1  

011f532b  shl         eax,0  

011f532e  mov         ecx,dword ptr [p]  

a = p[1];

011f5331  mov         dl,byte ptr [ecx+eax]  

011f5334  mov         byte ptr [a],dl  

第一種是在讀取時直接就把字串中的元素讀到暫存器

c1中,而第二種則要先把指標值讀到ecx中,再根據ecx讀取字元,顯然慢了。

附: 1、**段、唯讀資料段、已初始化讀寫資料段、未初始化資料段屬於靜態區域,而堆和棧屬於動態區域。 2、

**段、唯讀資料段和讀寫資料段將在鏈結之後產生,未初始化資料段將在程式初始化的時候開闢,而堆和棧將在程式的執行中分配和釋放。 3、

c語言程式分為映像和執行時兩種狀態,在編譯-彙編-鏈結後形成的映像中,將只包含**段(code 或 text)、唯讀資料段(rw data)和已初始化讀寫資料段(ro data)和讀寫資料段(rw data)。在程式執行之前,將動態生成未初始化資料段(bss),在程式的執行時還將動態形成堆(heap)區域和棧(stack)區域。一般來說,在靜態的映像檔案中,各個部分稱之為節(session),而在執行時的各個部分稱之為段(segment)。如果不詳細區分,可以統稱為段。 4、

函式體中定義的變數通常是在棧上,不需要在程式中進行管理,由編譯器處理。

用malloc,

new等分配記憶體的函式所分配的內存在堆上,程式必須保證再使用free

或delete

釋放,否則會發生記憶體洩漏。 5、

所有函式體外定義的是全域性變數,加了static後的變數不管是在函式內部或外部都放在全域性區。 6、

使用const定義的變數將放於程式的唯讀資料區。 7、

棧空間主要用於一下3種資料的儲存:函式內部的動態變數、函式的引數、函式的返回值。棧空間是動態開闢與**的,在函式呼叫過程中,如果函式呼叫的層次比較多,所需要的棧空間也逐漸加大,對於引數的傳遞和返回值,如果使用較大的結構體,在使用的棧空間也會比較大。

2023年5月14日

C語言程式的儲存區域

c語言程式的儲存區域 c語言編寫的程式經過編繹 鏈結後,將形成乙個統一的檔案,它由幾個部分組成,在程式執行時又會產生幾個其他部分,各個部分代表了不同的儲存區域 段 code or text 段由程式中的機器碼組成。在c語言中,程式語句進行編譯後,形成機器 在執行程式的過程中,cpu的程式計數器指向 ...

C C 變數儲存區域

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

C C 程式記憶體中變數儲存區域的溫習

四 總結 c語言在記憶體中分為下列幾個區 記憶體棧區 存放區域性變數名 記憶體堆區 存放new或者malloc出來的物件 常數區 存放區域性變數或者全域性變數的值 靜態區 用於存放全域性變數或者靜態變數 區 二進位制 接下來我們用c語言來檢視位址的變化 include include include...