1. 程式人生 > >函式的遞迴呼叫與棧

函式的遞迴呼叫與棧

一、棧
在說函式遞迴的時候,順便說一下棧的概念。
       棧是一個後進先出的壓入(push)和彈出(pop)式資料結構。在程式執行時,系統每次向棧中壓入一個物件,然後棧指標向上移動一個位置。當系統從棧中彈出一個物件時,最近進棧的物件將被彈出。然後棧指標向下移動一個位置。程式設計師經常利用棧這種資料結構來處理那些最適合用後進先出邏輯來描述的程式設計問題。這裡討論的程式中的棧在每個程式中都是存在的,它不需要程式設計師編寫程式碼去維護,而是由執行時系統自動處理。所謂的系統自動維護,實際上就是編譯器所產生的程式程式碼。儘管在原始碼中看不到它們,但程式設計師應該對此有所瞭解。


       再來看看程式中的棧是如何工作的。當一個函式(呼叫者)呼叫另一個函式(被呼叫者)時,執行時系統將把呼叫者的所有實參和返回地址壓入到棧中,棧指標將移到合適的位置來容納這些資料。最後進棧的是呼叫者的返回地址。當被呼叫者開始執行時,系統把被呼叫者的自變數壓入到棧中,並把棧指標再向下上移,以保證有足夠的空間儲存被呼叫者宣告的所有自變數。

當呼叫者把實參壓入棧後,被呼叫者就在棧中以自變數的形式建立了形參。被呼叫者內部的其他自變數也是存放在棧中的。由於這些進棧操作,棧指標已經移動所有這些區域性變數之上。但是被呼叫者記錄了它剛開始執行時的初始棧指標,以他為參考,用正或負的偏移值來訪問棧中的變數。當被呼叫者準備返回時,系統彈出棧中所有的自變數,這時棧指標移動了被呼叫者剛開始執行時的位置。接著被呼叫者返回,系統從棧中彈出返回地址,呼叫者就可以繼續執行了。當呼叫者繼續執行時,系統還將從棧中彈出呼叫者的實參,於是棧指標回到了呼叫發生前的位置。


二、遞迴
       遞迴,是函式實現的一個很重要的環節,很多程式中都或多或少的使用了遞迴函式。遞迴的意思就是函式自己呼叫自己本身,或者在自己函式呼叫的下級函式中呼叫自己。
       遞迴之所以能實現,是因為函式的每個執行過程都在棧中有自己的形參和區域性變數的拷貝,這些拷貝和函式的其他執行過程毫不相干。這種機制是當代大多數程式設計語言實現子程式結構的基礎,是使得遞迴成為可能。假定某個呼叫函式呼叫了一個被呼叫函式,再假定被呼叫函式又反過來呼叫了呼叫函式。這第二個呼叫就被稱為呼叫函式的遞迴,因為它發生在呼叫函式的當前執行過程執行完畢之前。而且,因為這個原先的呼叫函式、現在的被呼叫函式在棧中較低的位置有它獨立的一組引數和自變數,原先的引數和變數將不受影響,所以遞迴能正常工作。程式遍歷執行這些函式的過程就被稱為遞迴下降。
       程式設計師需保證遞迴函式不會隨意改變靜態變數和全域性變數的值,以避免在遞迴下降過程中的上層函數出錯。程式設計師還必須確保有一個終止條件來結束遞迴下降過程,並且返回到頂層。