我在C Primer Plus 的第 9 章中,作者介紹了稱為遞回的東西。我對他提供的示例程式的輸出感到困惑。需要你的家伙的一些幫助。
下面是代碼
#include <stdio.h>
void up_and_down(int);
int main(void)
{
up_and_down(1);
return 0;
}
void up_and_down(int n)
{
printf("Level %d: n location %p\n", n, &n); // 1
if (n < 4)
up_and_down(n 1);
printf("LEVEL %d: n location %p\n", n, &n); // 2
}
這是輸出
- 級別 1:n 位置 0x0012ff48
- 級別 2:n 位置 0x0012ff3c
- 級別 3:n 位置 0x0012ff30
- 級別 4:n 位置 0x0012ff24
- 級別 4:n 位置 0x0012ff24
- 級別 3:n 位置 0x0012ff30
- 級別 2:n 位置 0x0012ff3c
- 級別 1:n 位置 0x0012ff48
直到第 4 級為止沒有問題,其中 n = 4。此時,if 陳述句失敗,然后執行第二個 printf 函式。在第二個 printf 列印出來之后Level 4: n location 0x0012ff24,控制權不應該回到return 0主函式中嗎?為什么第二個 printf 繼續輸出其他三個 n 變數,特別是在向后方向。
作者解釋說這是因為
控制傳遞回呼叫它的函式(第 3 級呼叫)。在級別 3 呼叫中執行的最后一條陳述句是在 if 陳述句中呼叫級別 4。因此,級別 3 繼續執行以下陳述句,即列印陳述句 #2。這會導致列印 LEVEL 3。然后 Level3 結束,將控制權傳遞給 Level 2,它列印 LEVEL 2,依此類推。
他說的每一個字我都聽懂,但把這些句子加在一起,我根本不知道他在說什么。
為什么第二個 printf 繼續列印 3,2 和 1?尤其是按照這個順序。第二個 printf 是否意味著列印出所有 n 個變數?第二個 printf 行為背后的邏輯是什么。
uj5u.com熱心網友回復:
控制權不應該在主函式中傳回回傳 0 嗎?
不,不應該。讓我試著用一個類比來說服你。
假設你有四個功能:up_and_down_1(),up_and_down_2(),up_and_down_3()和up_and_down_4(),每個呼叫下一個里面。
現在,如果我在 的主體中up_and_down_1(),我呼叫up_and_down_2(),并且該函式結束(不管它做什么) - 控制回傳到up_and_down_1()呼叫后的下一行up_and_down_2()。這就是函式呼叫在 C 中的作業方式(另請參閱此處了解低級細節)。
嗯,遞回呼叫up_and_down(). 被呼叫的函式恰好是同一個函式并不重要。機器記住控制需要回傳到 中的某個行up_and_down(),區域變數設定為呼叫之前的方式 - 這不受對同一函式的內部呼叫這一事實的影響。內部呼叫是它自己的背景關系,在 的代碼中有它自己的控制傳遞up_and_down(),并且不影響外部呼叫。
我還可以推薦一個簡短的插圖視頻,介紹它在典型機器上的作業原理:
遞回編程中的呼叫堆疊和堆疊幀是什么?
uj5u.com熱心網友回復:
因為遞回并不特殊,當一個函式回傳時(任何函式;包括遞回函式呼叫),執行會從呼叫函式之前停止的地方開始。這意味著當您在第三級內部時,它會遞回呼叫第四級。當第四級呼叫回傳時,執行回到呼叫遞回函式之前的位置:第三級。
暫時忘記遞回。假設您有一個包含對 的呼叫的printf自定義函式,并且該自定義函式是從 內部呼叫的main。當printf回傳時,在哪里呢執行的簡歷?main,或者在您的自定義函式中它停止的地方?后者。您的函式需要在printf呼叫后完成代碼的執行,然后在執行完成后回傳到main. 遞回函式也是如此。
uj5u.com熱心網友回復:
它的解釋不必要地復雜。當你呼叫一個函式時,你會執行里面的任何代碼。當一個函式呼叫另一個函式時,它會執行代碼,然后回到原來的位置。為了這個例子,你可以想象它就像粘貼替換了 args 的內容,所以 up_and_down(1) 變成:
printf("Level %d: n location %p\n", n, &n); // n = 1
if (n < 4) { // n = 1
printf("Level %d: n location %p\n", n, &n); // n = 2
if (n < 4) // n = 2
... paste again with n = 3
printf("LEVEL %d: n location %p\n", n, &n); // n = 2
}
printf("LEVEL %d: n location %p\n", n, &n); // n = 1
這基本上是:
print("enter 1")
if (...)
print("enter 2")
if (...)
print("enter 3")
if (...)
print("enter 4")
// if evaluates to false here, so we dont go deeper
print("exit 4")
print("exit 3")
print("exit 2")
print("exit 1")
uj5u.com熱心網友回復:
讓我們從 n=1 開始,它列印第一個 printf ,然后它進入條件并再次呼叫相同的函式,當該函式完成其作業時,程式將移動到下一行,即第二個 printf ,所以真的第二個 printf 沒有被跳過,它只是在等待函式呼叫完成,這發生在 n=2 和 n=3 等中,
uj5u.com熱心網友回復:
每個函式呼叫都會“阻塞”,直到被呼叫的函式回傳。
級別 1 將在級別 1 到達第二個之前呼叫級別 2 printf。但是,Level 2 會在到達第二個printf并最終回傳之前呼叫 Level 3 。
這將持續所有級別,直到我們到達第 4 級。在第 4 級,if 陳述句評估為false,因此up_and_down(n 1)永遠不會到達,因此第 5 級將永遠不會成為事物。
因此,第 4 級是第一個達到其隱含return. 第 4 級阻止了第 3 級,因此在第 4 級沒有障礙的情況下,第 3 級可以繼續執行,并且下一條指令是printf("LEVEL %d......<something>", n, &n);where n = 3。之后,第 3 級達到其return并解鎖第 2 級,依此類推。
遞回就像一個堆疊,而不是一個佇列。
void up_and_down(int n)
{
printf("Level %d: n location %p\n", n, &n); // 1
if (n < 4)
up_and_down(n 1);
printf("LEVEL %d: n location %p\n", n, &n); // 2
return; // Return and unblock the function level that invoked this level, which is level n - 1
}
如果你仍然不理解遞回,請再讀一遍。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/326813.html
上一篇:在遞回的基本情況下回傳None的目的是否只是用作填充物,然后自然而然地執行呼叫堆疊中的頂級遞回呼叫?
下一篇:根據id遞回獲取樹段
