您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“C++中堆棧與函數(shù)如何調(diào)用”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學習一下“C++中堆棧與函數(shù)如何調(diào)用”這篇文章吧。
一 C++程序內(nèi)存分配
1) 在棧上創(chuàng)建。在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元都在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時這些存儲單元自動被釋放。棧內(nèi)存分配運算內(nèi)置于處理器的指令集中,一般使用寄存器來存取,效率很高,但是分配的內(nèi)存容量有限。
2) 從堆上分配,亦稱動態(tài)內(nèi)存分配。程序在運行的時候用malloc或new申請任意多少的內(nèi)存,程序員自己負責在何時用free或delete來釋放內(nèi)存。動態(tài)內(nèi)存的生存期由程序員自己決定,使用非常靈活。
3) 從靜態(tài)存儲區(qū)域分配。內(nèi)存在程序編譯的時候就已經(jīng)分配好,這塊內(nèi)存在程序的整個運行期間都存在。例如全局變量,static變量。
4) 文字常量分配在文字常量區(qū),程序結(jié)束后由系統(tǒng)釋放。
5)程序代碼區(qū)。
經(jīng)典實例:(代碼來自網(wǎng)絡高手,沒有找到原作者)
Code
#include <string>
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
二 三種內(nèi)存對象的比較
棧對象的優(yōu)勢是在適當?shù)臅r候自動生成,又在適當?shù)臅r候自動銷毀,不需要程序員操心;而且棧對象的創(chuàng)建速度一般較堆對象快,因為分配堆對象時,會調(diào)用operator new操作,operator new會采用某種內(nèi)存空間搜索算法,而該搜索過程可能是很費時間的,產(chǎn)生棧對象則沒有這么麻煩,它僅僅需要移動棧頂指針就可以了。但是要注意的是,通常??臻g容量比較小,一般是1MB~2MB,所以體積比較大的對象不適合在棧中分配。特別要注意遞歸函數(shù)中最好不要使用棧對象,因為隨著遞歸調(diào)用深度的增加,所需的??臻g也會線性增加,當所需??臻g不夠時,便會導致棧溢出,這樣就會產(chǎn)生運行時錯誤。
堆對象創(chuàng)建和銷毀都要由程序員負責,所以,如果處理不好,就會發(fā)生內(nèi)存問題。如果分配了堆對象,卻忘記了釋放,就會產(chǎn)生內(nèi)存泄漏;而如 果已釋放了對象,卻沒有將相應的指針置為NULL,該指針就是所謂的“懸掛指針”,再度使用此指針時,就會出現(xiàn)非法訪問,嚴重時就導致程序崩潰。但是高效的使用堆對象也可以大大的提高代碼質(zhì)量。比如,我們需要創(chuàng)建一個大對象,且需要被多個函數(shù)所訪問,那么這個時候創(chuàng)建一個堆對象無疑是良好的選擇,因為我們通過在各個函數(shù)之間傳遞這個堆對象的指針,便可以實現(xiàn)對該對象的共享,相比整個對象的傳遞,大大的降低了對象的拷貝時間。另外,相比于棧空間,堆的容量要大得多。實際上,當物理內(nèi)存不夠時,如果這時還需要生成新的堆對象,通常不會產(chǎn)生運行時錯誤,而是系統(tǒng)會使用虛擬內(nèi)存來擴展實際的物理內(nèi)存。
靜態(tài)存儲區(qū)。所有的靜態(tài)對象、全局對象都于靜態(tài)存儲區(qū)分配。關(guān)于全局對象,是在main()函數(shù)執(zhí)行前就分配好了的。其實,在main()函數(shù)中的顯示代 碼執(zhí)行之前,會調(diào)用一個由編譯器生成的_main()函數(shù),而_main()函數(shù)會進行所有全局對象的的構(gòu)造及初始化工作。而在main()函數(shù)結(jié)束之 前,會調(diào)用由編譯器生成的exit函數(shù),來釋放所有的全局對象。比如下面的代碼:
void main(void) |
實際上,被轉(zhuǎn)化成這樣:
void main(void) |
除了全局靜態(tài)對象,還有局部靜態(tài)對象通和class的靜態(tài)成員,局部靜態(tài)對象是在函數(shù)中定義的,就像棧對象一樣,只不過,其前面多了個static關(guān)鍵字。局部靜態(tài)對象的生命期是從其所在函數(shù)第一次被調(diào)用,更確切地說,是當?shù)谝淮螆?zhí)行到該靜態(tài)對象的聲明代碼時,產(chǎn)生該靜態(tài)局部對象,直到整個程序結(jié)束時,才銷毀該對象。class的靜態(tài)成員的生命周期是該class的第一次調(diào)用到程序的結(jié)束。
三 函數(shù)調(diào)用與堆棧
1)編譯器一般使用棧來存放函數(shù)的參數(shù),局部變量等來實現(xiàn)函數(shù)調(diào)用。有時候函數(shù)有嵌套調(diào)用,這個時候棧中會有多個函數(shù)的信息,每個函數(shù)占用一個連續(xù)的區(qū)域。一個函數(shù)占用的區(qū)域被稱作幀(frame)。同時棧是線程獨立的,每個線程都有自己的棧。例如下面簡單的函數(shù)調(diào)用:
另外函數(shù)堆棧的清理方式?jīng)Q定了當函數(shù)調(diào)用結(jié)束時由調(diào)用函數(shù)或被調(diào)用函數(shù)來清理函數(shù)幀,在VC中對函數(shù)棧的清理方式由兩種:
參數(shù)傳遞順序 | 誰負責清理參數(shù)占用的堆棧 | |
__stdcall | 從右到左 | 被調(diào)函數(shù) |
__cdecl | 從右到左 | 調(diào)用者 |
2) 有了上面的知識為鋪墊,我們下面細看一個函數(shù)的調(diào)用時堆棧的變化:
代碼如下:
Code
int Add(int x, int y)
{
return x + y;
}
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
對上面的代碼,我們分為四步,當然我們只畫出了我們的代碼對堆棧的影響,其他的我們假設它們不存在,哈哈!
第一,int *pi = new int(10); int *pj = new int(20); int result = 0; 堆棧變化如下:
第二,Add(*pi,*pj);堆棧如下:
第三,將Add的結(jié)果給result,堆棧如下:
第四,delete pi; delete pj; 堆棧如下:
第五,當main()退出后,堆棧如下,等同于main執(zhí)行前,哈哈!
以上是“C++中堆棧與函數(shù)如何調(diào)用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。