- 相關(guān)推薦
C語(yǔ)言中堆和棧的區別有哪些
在計算機領(lǐng)域,堆棧是一個(gè)不容忽視的概念,對于很多的初學(xué)著(zhù)來(lái)說(shuō),堆棧是一個(gè)很模糊的概念。本文是百分網(wǎng)小編搜索整理的關(guān)于C語(yǔ)言中堆和棧的區別,供參考閱讀,希望對大家有所幫助!想了解更多相關(guān)信息請持續關(guān)注我們應屆畢業(yè)生考試網(wǎng)!
堆棧:一種數據結構、一個(gè)在程序運行時(shí)用于存放的地方,這可能是很多初學(xué)者的認識,因為我曾經(jīng)就是這么想的和匯編語(yǔ)言中的堆棧一詞混為一談。我身邊的一些編程的朋友以及在網(wǎng)上看帖遇到的朋友中有好多也說(shuō)不清堆棧,所以我想有必要給大家分享一下我對堆棧的看法,有說(shuō)的不對的地方請朋友們不吝賜教,這對于大家學(xué)習會(huì )有很大幫助。
一.前言:
C語(yǔ)言程序經(jīng)過(guò)編譯連接后形成編譯、連接后形成的二進(jìn)制映像文件由棧,堆,數據段(由三部分部分組成:只讀數據段,已經(jīng)初始化讀寫(xiě)數據段,未初始化數據段即BBS)和代碼段組成,如下圖所示:
1.棧區(stack):由編譯器自動(dòng)分配釋放,存放函數的參數值,局部變量等值。其操作方式類(lèi)似于數據結構中的棧。
2.堆區(heap):一般由程序員分配釋放,若程序員不釋放,則可能會(huì )引起內存泄漏。注堆和數據結構中的堆棧不一樣,其類(lèi)是與鏈表。
3.程序代碼區:存放函數體的二進(jìn)制代碼。
4.數據段:由三部分組成:
1>只讀數據段:
只讀數據段是程序使用的一些不會(huì )被更改的數據,使用這些數據的方式類(lèi)似查表式的操作,由于這些變量不需要更改,因此只需要放置在只讀存儲器中即可。一般是const修飾的變量以及程序中使用的文字常量一般會(huì )存放在只讀數據段中。
2>已初始化的讀寫(xiě)數據段:
已初始化數據是在程序中聲明,并且具有初值的變量,這些變量需要占用存儲器的空間,在程序執行時(shí)它們需要位于可讀寫(xiě)的內存區域內,并且有初值,以供程序運行時(shí)讀寫(xiě)。在程序中一般為已經(jīng)初始化的全局變量,已經(jīng)初始化的靜態(tài)局部變量(static修飾的已經(jīng)初始化的變量)
3>未初始化段(BSS):
未初始化數據是在程序中聲明,但是沒(méi)有初始化的變量,這些變量在程序運行之前不需要占用存儲器的空間。與讀寫(xiě)數據段類(lèi)似,它也屬于靜態(tài)數據區。但是該段中數據沒(méi)有經(jīng)過(guò)初始化。未初始化數據段只有在運行的初始化階段才會(huì )產(chǎn)生,因此它的大小不會(huì )影響目標文件的大小。在程序中一般是沒(méi)有初始化的全局變量和沒(méi)有初始化的靜態(tài)局部變量。
二.堆和棧的區別
1.申請方式
(1)棧(satck):由系統自動(dòng)分配。例如,聲明在函數中一個(gè)局部變量int b;系統自動(dòng)在棧中為b開(kāi)辟空間。
(2)堆(heap):需程序員自己申請(調用malloc,realloc,calloc),并指明大小,并由程序員進(jìn)行釋放。容易產(chǎn)生memory leak.
eg:char p;
p = (char *)malloc(sizeof(char));
但是,p本身是在棧中。
2.申請大小的限制
(1)棧:在windows下棧是向底地址擴展的數據結構,是一塊連續的內存區域(它的生長(cháng)方向與內存的生長(cháng)方向相反)。棧的大小是固定的。如果申請的空間超過(guò)棧的剩余空間時(shí),將提示overflow。
(2)堆:堆是高地址擴展的數據結構(它的生長(cháng)方向與內存的生長(cháng)方向相同),是不連續的內存區域。這是由于系統使用鏈表來(lái)存儲空閑內存地址的,自然是不連續的,而鏈表的遍歷方向是由底地址向高地址。堆的大小受限于計算機系統中有效的虛擬內存。
3.系統響應:
(1)棧:只要棧的空間大于所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。
(2)堆:首先應該知道操作系統有一個(gè)記錄空閑內存地址的鏈表,但系統收到程序的申請時(shí),會(huì )遍歷該鏈表,尋找第一個(gè)空間大于所申請空間的堆結點(diǎn),然后將該結點(diǎn)從空閑鏈表中刪除,并將該結點(diǎn)的空間分配給程序,另外,對于大多數系統,會(huì )在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的free語(yǔ)句才能正確的釋放本內存空間。另外,找到的堆結點(diǎn)的大小不一定正好等于申請的大小,系統會(huì )自動(dòng)的將多余的那部分重新放入空閑鏈表中。
說(shuō)明:對于堆來(lái)講,對于堆來(lái)講,頻繁的new/delete勢必會(huì )造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。對于棧來(lái)講,則不會(huì )存在這個(gè)問(wèn)題,
4.申請效率
(1)棧由系統自動(dòng)分配,速度快。但程序員是無(wú)法控制的
(2)堆是由malloc分配的內存,一般速度比較慢,而且容易產(chǎn)生碎片,不過(guò)用起來(lái)最方便。
5.堆和棧中的存儲內容
(1)棧:在函數調用時(shí),第一個(gè)進(jìn)棧的主函數中后的下一條語(yǔ)句的地址,然后是函數的各個(gè)參數,參數是從右往左入棧的,然后是函數中的局部變量。注:靜態(tài)變量是不入棧的。
當本次函數調用結束后,局部變量先出棧,然后是參數,最后棧頂指針指向最開(kāi)始存的地址,也就是主函數中的下一條指令,程序由該點(diǎn)繼續執行。
(2)堆:一般是在堆的頭部用一個(gè)字節存放堆的大小。
6.存取效率
(1)堆:char *s1=”hellow tigerjibo”;是在編譯是就確定的
(2)棧:char s1[]=”hellow tigerjibo”;是在運行時(shí)賦值的;用數組比用指針速度更快一些,指針在底層匯編中需要用edx寄存器中轉一下,而數組在棧上讀取。
補充:
棧是機器系統提供的數據結構,計算機會(huì )在底層對棧提供支持:分配專(zhuān)門(mén)的寄存器存放棧的地址,壓棧出棧都有專(zhuān)門(mén)的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很復雜的,例如為了分配一塊內存,庫函數會(huì )按照一定的算法(具體的算法可以參考數據結構/操作系統)在堆內存中搜索可用的足夠大小的空間,如果沒(méi)有足夠大小的空間(可能是由于內存碎片太多),就有可能調用系統功能去增加程序數據段的內存空間,這樣就有機會(huì )分到足夠大小的內存,然后進(jìn)行返回。顯然,堆的效率比棧要低得多。
7.分配方式:
(1)堆都是動(dòng)態(tài)分配的,沒(méi)有靜態(tài)分配的堆。
(2)棧有兩種分配方式:靜態(tài)分配和動(dòng)態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動(dòng)態(tài)分配由alloca函數進(jìn)行分配,但是棧的動(dòng)態(tài)分配和堆是不同的。它的動(dòng)態(tài)分配是由編譯器進(jìn)行釋放,無(wú)需手工實(shí)現。
【C語(yǔ)言中堆和棧的區別有哪些】相關(guān)文章:
C語(yǔ)言中棧的表示和實(shí)現04-19
c語(yǔ)言stack(棧)和heap(堆)的使用01-28
c語(yǔ)言stack(棧)和heap(堆)的使用詳解02-13
c語(yǔ)言指針運用中堆和棧的區別03-05
Java中的堆和棧的區別05-23
Java堆、棧和常量池的解釋03-01
關(guān)于java中堆和棧的區別01-13