1. 程式人生 > >C/C++ STACK &HEAP 區別

C/C++ STACK &HEAP 區別

堆:順序隨意 
棧:先進後出 
堆和棧的區別 
一、預備知識—程式的記憶體分配 
一個由c/C++編譯的程式佔用的記憶體分為以下幾個部分 
1、棧區(stack)— 由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧 
2、堆區(heap) — 一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可能由OS回收 。注意它與資料結構中的堆是兩回事,分配方式倒是類似於連結串列,呵呵。 
3、全域性區(靜態區)(static)—,全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域, 未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。 - 程式結束後有系統釋放 

4、文字常量區 —常量字串就是放在這裡的。 程式結束後由系統釋放  
5、程式程式碼區—存放函式體的二進位制程式碼。 
二、例子程式 
這是一個前輩寫的,非常詳細 
//main.cpp  
int a = 0; 全域性初始化區 
char *p1; 全域性未初始化區 
main() 
{     
     int b; 棧 
     char s[] = "abc"; 棧  
     char *p2; 棧  
     char *p3 = "123456"; 123456\0在常量區,p3在棧上。  
     static int c =0; 全域性(靜態)初始化區  
     p1 = (char *)malloc(10);  

     p2 = (char *)malloc(20);  
     分配得來得10和20位元組的區域就在堆區。  
     strcpy(p1, "123456"); 123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。  
}  
二、堆和棧的理論知識 
2.1申請方式 
stack:由系統自動分配。 例如,宣告在函式中一個區域性變數 int b; 系統自動在棧中為b開闢空間 
heap:需要程式設計師自己申請,並指明大小,在c中malloc函式如p1 = (char *)malloc(10);在C++中用new運算子如p2 = (char *)malloc(10);但是注意p1、p2本身是在棧中的 

2.2申請後系統的響應 
棧:只要棧的剩餘空間大於所申請空間,系統將為程式提供記憶體,否則將報異常提示棧溢位。 
堆:首先應該知道作業系統有一個記錄空閒記憶體地址的連結串列,當系統收到程式的申請時,會遍歷該連結串列,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點連結串列中刪除,並將該結點的空間分配給程式,另外,對於大多數系統,會在這塊記憶體空間中的首地址處記錄本次分配的大小,這樣,程式碼中的delete語句才能正確的釋放本記憶體空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒連結串列中。  
2.3申請大小的限制 
棧:在Windows下,棧是向低地址擴充套件的資料結構,是一塊連續的記憶體的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。 
堆:堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。  
2.4申請效率的比較: 
棧由系統自動分配,速度較快。但程式設計師是無法控制的。 
堆是由new分配的記憶體,一般速度比較慢,而且容易產生記憶體碎片,不過用起來最方便. 另外,在WINDOWS下,最好的方式是用VirtualAlloc分配記憶體,他不是在堆,也不是在棧是直接在程序的地址空間中保留一快記憶體,雖然用起來最不方便。但是速度快,也最靈活  
2.5堆和棧中的儲存內容 
棧: 在函式呼叫時,第一個進棧的是主函式中後的下一條指令(函式呼叫語句的下一條可執行語句)的地址,然後是函式的各個引數,在大多數的C編譯器中,引數是由右往左入棧的,然後是函式中的區域性變數。注意靜態變數是不入棧的。當本次函式呼叫結束後,區域性變數先出棧,然後是引數,最後棧頂指標指向最開始存的地址,也就是主函式中的下一條指令,程式由該點繼續執行。  
堆:一般是在堆的頭部用一個位元組存放堆的大小。堆中的具體內容有程式設計師安排。  
2.6存取效率的比較  
char s1[] = "aaaaaaaaaaaaaaa";  
char *s2 = "bbbbbbbbbbbbbbbbb";  
aaaaaaaaaaa是在執行時刻賦值的;而bbbbbbbbbbb是在編譯時就確定的;但是,在以後的存取中,在棧上的陣列比指標所指向的字串(例如堆)快。  
比如: 
#include 
void main() 
{     
     char a = 1;      
     char c[] = "1234567890";      
     char *p ="1234567890";     
     a = c[1];      
     a = p[1];      
     return;      
}  
對應的彙編程式碼  
10: a = c[1];  
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] 
0040106A 88 4D FC mov byte ptr [ebp-4],cl  
11: a = p[1];  
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]  
00401070 8A 42 01 mov al,byte ptr [edx+1]  
00401073 88 45 FC mov byte ptr [ebp-4],al  
第一種在讀取時直接就把字串中的元素讀到暫存器cl中,而第二種則要先把指標值讀到edx中,在根據edx讀取字元,顯然慢了。  
2.7小結: 
堆和棧的區別可以用如下的比喻來看出:使用棧就象我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。 使用堆就象是自己動手做喜歡吃的菜餚,比較麻煩,但是比較符合自己的口味,而且自由度大。  
堆和棧的區別主要分:  
作業系統方面的堆和棧,如上面說的那些,不多說了。還有就是資料結構方面的堆和棧,這些都是不同的概念。這裡的堆實際上指的就是(滿足堆性質的)優先佇列的一種資料結構,第1個元素有最高的優先權;棧實際上就是滿足先進後出的性質的數學或資料結構。雖然堆疊,堆疊的說法是連起來叫,但是他們還是有很大區別的,連著叫只是由於歷史的原因。 
=======================================
---------------------------------------
=======================================
轉一篇文章:


可能許多人對記憶體分配上的“棧 stack”和“堆 heap”還不是很明白。包括一些科班出身的人也不明白這兩個概念。我不想過多的說這兩個東西。簡單的來講,stack上分配的記憶體系統自動釋放,heap上分配的記憶體,系統不釋放,哪怕程式退出,那一塊記憶體還是在那裡。stack一般是靜態分配記憶體,heap上一般是動態分配記憶體。  

由malloc系統函式分配的記憶體就是從堆上分配記憶體。從堆上分配的記憶體一定要自己釋放。用free釋放,不然就是術語——“記憶體洩露”(或是“記憶體漏洞”)—— Memory Leak。於是,系統的可分配記憶體會隨malloc越來越少,直到系統崩潰。還是來看看“棧記憶體”和“堆記憶體”的差別吧。  

棧記憶體分配  
—————--------------------------------------------------  
char*  
AllocStrFromStack()  
{  
char pstr[100];  
return pstr;  
}  


堆記憶體分配  
—————--------------------------------------------------char*  
AllocStrFromHeap(int len)  
{  
char *pstr;  

if ( len <= 0 ) return NULL;  
return ( char* ) malloc( len );  
}  

對於第一個函式,那塊pstr的記憶體在函式返回時就被系統釋放了。於是所返回的char*什麼也沒有。而對於第二個函式,是從堆上分配記憶體,所以哪怕是程式退出時,也不釋放,所以第二個函式的返回的記憶體沒有問題,可以被使用。但一定要呼叫free釋放,不然就是Memory Leak!  

在堆上分配記憶體很容易造成記憶體洩漏,這是C/C++的最大的“剋星”,如果你的程式要穩定,那麼就不要出現Memory Leak。所以,我還是要在這裡千叮嚀萬囑付,在使用malloc系統函式(包括calloc,realloc)時千萬要小心。  

記得有一個UNIX上的服務應用程式,大約有幾百的C檔案編譯而成,執行測試良好,等使用時,每隔三個月系統就是down一次,搞得許多人焦頭爛額,查不出問題所在。只好,每隔兩個月人工手動重啟系統一次。出現這種問題就是Memery Leak在做怪了,在C/C++中這種問題總是會發生,所以你一定要小心。 
我保證,做過許多C/C++的工程的程式設計師,都會對malloc或是new有些感冒。當你什麼時候在使用malloc和new時,有一種輕度的緊張和惶恐的感覺時,你就具備了這方面的修養了。  

對於malloc和free的操作有以下規則:  

1) 配對使用,有一個malloc,就應該有一個free。(C++中對應為new和delete)  
2) 儘量在同一層上使用,不要像上面那種,malloc在函式中,而free在函式外。最好在同一呼叫層上使用這兩個函式。  
3) malloc分配的記憶體一定要初始化。free後的指標一定要設定為NULL。  

注:雖然現在的作業系統(如:UNIX和Win2k/NT)都有程序記憶體跟蹤機制,也就是如果你有沒有釋放的記憶體,作業系統會幫你釋放。但作業系統依然不會釋放你程式中所有產生了Memory Leak的記憶體,所以,最好還是你自己來做這個工作。(有的時候不知不覺就出現Memory Leak了,而且在幾百萬行的程式碼中找無異於海底撈針,Rational有一個工具叫Purify,可能很好的幫你檢查程式中的Memory Leak)

相關推薦

C/C++ STACK &HEAP 區別

堆:順序隨意 棧:先進後出 堆和棧的區別 一、預備知識—程式的記憶體分配 一個由c/C++編譯的程式佔用的記憶體分為以下幾個部分 1、棧區(stack)— 由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧 2、堆區(heap) —

C++中堆(heap)和棧(stack)的區別(面試中被問到的題目)

說起會了解這個東西,還是比較尷尬的,在學校裡面老師一般不會講解C++的堆和棧,大多數人瞭解的堆和棧是資料結構裡面的概念,而這裡一般面試官想問的是C++的記憶體分割槽管理方式。 首先說明,在C++中,記憶體分為5個區:堆、佔、自由儲存區、全域性/靜態儲存區、常量儲存區 棧:

C/C++中棧(stack)與堆(heap)的區別

棧(stack) 由編譯器自動分配釋放管理。區域性變數及每次函式呼叫時返回地址、以及呼叫者的環境資訊(例如某些機器暫存器)都存放在棧中。新被呼叫的函式在棧上為其自動和臨時變數分配儲存空間。 堆(he

【高質量C++/C總結6】記憶體管理——堆(stack)棧(heap

說在開始: 我提煉了《C++ Primer》、《侯捷C++》、《高質量程式設計指南——C/C++語言》等資料中的重要部分,並總結成此博文。其中涉及到許多我個人對C++的理解,如若有不合理之處,還請朋友們多多指出,我會虛心接受每一個建議。同時,我將實現程式碼放到了我的GitHub上ht

C++之Binary Heap/Max Heap

right pac col log parent this success ren ins 1 #include <iostream> 2 #include <time.h> 3 #include <random> 4

【轉】Visual C++ 和 C++ 有什麽區別

業界 流行 編譯器 gtk+ 語言 開發 多種實現 廠商 計算 有位同學問我“Visual C++和C++有什麽區別?”,這的確是初學者會感到困惑的問題,比較常見。除此之外,還有“先學C++好,還是先學Visual C++好?”,都屬於同樣的概念不明的問題,就比

B/S架構與C/S架構的區別

安裝 出現 部分 重要 biztalk 趨勢 硬件 管理 校驗 區別 硬件環境不同: C/S 一般建立在專用的網絡上, 小範圍裏的網絡環境, 局域網之間再通過專門服務器提供連接和數據交換服務. B/S 建立在廣域網之上的, 不必是專門的網絡硬件環境

201671010139 2016-2017-2 JAVA 和C語言的語法區別

tro 特點 建立 優點 cor ext 虛函數 ref strong   java和c語言的語法上有很多相似的地方,但也有很多不同。 一,在初始值的區別   在C語言中,是可以不初始化使用的   而在JAVA中,是必須初始化值的 二,在抽象方法或抽象類的區別   C語言的

B/S架構和C/S架構的區別

優點 安裝客戶端 使用 lpad web 賬號體系 lsp 後臺 ket C/S架構的優缺點:*優點:1.客戶端因為是獨立設計,所以可以實現個性化2.因為客戶端是需要進行安裝的,可以不需要重復安裝和加載3.因為客戶端是獨立開發的,所以有能力對客戶端進行安全設計4

CC++結構體的區別

mage contain 裏的 clas 存在 prot 使用 構造函數 lai C的結構體內不允許有函數存在,C++允許有內部成員函數,且允許該函數是虛函數。所以C的結構體是沒有構造函數、析構函數、和this指針的。 C的結構體對內部成員變量的訪問權限只能是public

C#與.Net的區別

客戶 技術 選擇 希望 靈活 平臺 found web瀏覽器 簡便 區分.net與C# net(dotnet):含義 一般指.Net Framework框架,是Microsoft為開發應用程序而創建的一個具有革命意義的平臺, 內容 主要包含一個龐大的代碼癢,可

C/C++中near和far的區別

語言 補充 detail net 計算機體系結構 偏移 單元 體系結構 all C/C++中near和far的區別 關鍵字near和far受目標計算機體系結構的影響。目前編程中使用不多。 near關鍵字創建一個指向可尋址內存低端部分的目標指針。這些

C語言的的free和c++的delete的區別

表示 log 一個數 重復 csdn 應用 malloc null 析構 首先free對應的是malloc;delete對應的是new;free用來釋放malloc出來動態內存,delete用來釋放new出來的動態內存空間。 應用的區別為: 1. 數組的時候int *p=(

C++和java的區別和聯系

討論 重要 優勢 net 類型轉換 總結 沒有 中間件 釋放 今晚,數院的一個兄弟借我Java課本,順便問了一句“Java和C++到底有啥區別啊”。一下子有點問蒙了,“啊額.....運行平臺不同....” "一個在高層,一個在底層...." "執行效率不同......

C# show和showdialog區別

更多 comm isp 應該 常見 解釋 方式 不存在 close 簡單地說他們的區別就是show彈出來的窗體和父窗體(上一個窗體的簡稱)是屬於同一等級的,這兩個窗體可以同時存在而且可以隨意切換,但是showdialog彈出來的窗體就不能這樣,他永遠是被置頂的,如果

C++ new 和malloc 區別

clas 區別 let void 操作符 類型 new 需要 調用 1.分配地方不同,malloc是堆上面,new是自由存儲區域 2.malloc/delete是函數,new/delete是操作符,可以重載 3.malloc 要指定大小,返回的是void*指針,開辟的是空空

C/C++之巨集、行內函數和普通函式的區別

轉載:https://www.cnblogs.com/ht-927/p/4726570.html C/C++之巨集、行內函數和普通函式的區別 行內函數的執行過程與帶引數巨集定義很相似,但引數的處理不同。帶引數的巨集定義並不對引數進行運算,而是直接替換;行內函數首先是函式,這就意味著函式的很多

FastSocket(C/C++)、FastSocket.NET(C#)與SuperSocket(純C#) 開源庫的區別、介紹、使用方法

一、FastSocket與SuperSocket  區別 裡面包含了視訊教程。 我們到底選擇哪一款開源的Socket框架?https://blog.csdn.net/abennet/article/details/79399713 二、新浪的FastSocket介紹

C語言中%c與%s的區別與劃分

%c格式對應的是單個字元,%s格式對應的是字串。例:char a;char b[20];scanf("%c",&a); //只能輸入一個字元。scanf("%s",b); //可以輸入一串不超過20字元的字串。 %c對應型別為char, %s對應型別為char , 即字串. 用作

CC++的聯絡與區別

面向過程的思路:分析解決問題所需的步驟,用函式把這些步驟依次實現。 面向物件的思路:把構成問題的事務分解為各個物件,建立物件的目的,不是完成一個步驟,而是描述某個事務在解決整個問題步驟中的行為。 從上述描述可以看出,其實面向物件和麵向過程是兩種思考解決問題的方式,其差異主要在於思考的角度。