[英]Recursion flow in c language and how the output is printed
我的印刷價值如何?
我知道遞歸一次又一次地調用自己。 據我說,該函數應該返回空值,因為在打印之前調用了該函數。 printf
如何工作?
recur(int i)
{
if(i<0)
return 0;
recur(--i);
printf("%d",i);
recur(--i);
}
main()
{
recur(2);
}
The output of this program is
-1
0
1
-1
有人可以解釋它是如何工作的嗎?
要了解會發生什么,您必須了解遞歸如何工作。 每個遞歸函數都需要一個測試條件來中斷遞歸和一個遞歸調用。 您將if (i < 0)
作為測試條件,然后進行兩次遞歸調用,並在它們之間進行printf
調用。
那么這是如何工作的呢?
您可以考慮遞歸和結束操作,直到觸發退出條件為止-然后隨着遞歸調用的返回而放松。 讓我們在這里看看它是如何工作的。
遞歸
當您從main
recur(2)
開始時,邏輯采用哪種路徑結束退出狀態?
如果簡化功能並專注於滿足測試條件之前發生的情況,您將獲得類似於以下內容的信息:
void recur (int i) {
if (i < 0)
return;
recur (--i);
/* comes after return */
}
讓我們繼續進行下去。 在第一次調用, i = 2
,以便--1
預decriment發生使i = 1
, recur (1)
執行。 下次調用i = 0
, recur (0)
調用recur (0)
。 最后, i = -1
,並且出現第一個recur(-1)
,因此if (i < 0)
執行if (i < 0)
並調用return
。
怎么辦? -正在放松...
請看上面的簡化功能。 當您return
,您將從對recur(--i)
的最后一次調用return
,因此控制權現在在第一個recur(-1)
之后傳遞給下一個命令(顯示為/* comes after return */
)完整功能中的下一個命令?
printf("%d\n", i);
recur (--i);
第一次出現時, i
的值是多少? (提示: -1
)。
所以調用了printf
,然后接下來呢? 您的第二次recur(--i)
。 i = -2
, if (i < 0) return;
觸發,您退出第二個recur(-2)
-沒有后續命令,並且該函數調用現已完成。
現在,控制權退回到上一個調用,其中i
現在為0
,調用printf
,並使用i = -1
輸入第二個recur(--i)
,只需再次按return
然后再return
一個級別到i = 1
從第一個recur(--i)
調用再次返回,將輸出1
。
輸入第二個recur(--i)
調用,在遞減i = 0
,您現在又遞歸到第一個i = -1
再次觸發return
,這導致contol在最終-1
打印時傳遞給printf
。
現在,您以i = -2
觸發第二個recur(--i)
觸發return
並完成函數調用和遞歸。
因此,如果您通過兩次遞歸調用返回到遞歸函數的控件,並查看每次到達printf
,您將輸出-1, 0, 1, -1
。
仍然認為具有多個遞歸調用的遞歸函數是一個好主意嗎?
(如果您是阿司匹林推銷員,則可能會出現這種情況,否則,最好避免使用它們,除非它們是您唯一合理的選擇)
進行此類操作的唯一方法是(1)與調試器交朋友,並單步執行代碼,以保留在調用時輸入了便箋的草稿,或者(2)將函數復制並粘貼到頁面下方在每個級別上跟蹤遞歸調用的狀態,並逐步進行。
始終是良好的學習經驗,但是如果有過程解決方案可用,則邏輯會更加簡單明了,並且可以避免每次遞歸調用的函數調用開銷。 遞歸函數占有一席之地,並且為某些問題提供了非常優雅的解決方案。 但是您必須注意,每次調用時都會為局部變量分配一個單獨的函數堆棧和空間,遞歸將發生多少次,這可能會導致StackOverflow。
當您調用recur(2);
,此時
recur(--i);
調用recur(1)
,然后再次到達該點時,調用recur(0);
被調用,然后再次調用recur(-1);
叫做。 recur(-1);
調用立即返回,因為if(i<0) return 0;
。
recur(0);
調用,其中i
現在為-1
,然后執行打印並返回(它的確recur(--i);
但這時為-2
)。 接下來, recur(1)
調用(現在i
為0
)進行打印,並且recur(1)
,該返回。
最后,原始recur(2);
調用(其中i
為1)打印並調用另一個recur(0);
,如我們所見,導致-1
被打印。 這將導致輸出-101-1
,或者如果您向每個打印添加換行符,則將看到輸出。
附帶一提,我建議您將主要功能編寫為
int main()
{
recur(2);
return 0; // return value of 0 indicates successful program execution
}
並將recur(int i)
的簽名更改為void recur(int i)
並return 0;
剛return;
。
根據我的說法,該函數應該在打印前調用該函數時返回空值。 printf是如何工作的?
總結起來,它之所以有用,是因為並非所有的遞歸調用都在做進一步的遞歸調用。 他們僅在某些條件下執行遞歸調用,如果不執行該遞歸調用,它們將在某個時刻結束,從而允許調用它的函數繼續。
問題是您在打印出該值之前正在調用函數。
recur(int i)
{
if(i<0)
return 0;
recur(--i);
printf("%d",i);
recur(--i);
}
您正在main
函數中調用recur(2)
,因為i=2
所以第一個if(i<0)
不返回0。 然后使用值1 recur(1)
調用函數recur
在這種情況下, if(i<0)
也不會返回0,因為i=1
不是函數recur(0)
被調用為0。
if(i<0)
仍然不返回0,因為i=0
並且您的函數被recur(-1)
調用。
然后,由於i=-1
if(i<0)
returns 0
。
現在我們開始print()
輸出我們之前給函數的值。 那個是print(-1)
因為它是我們函數擁有的最后一個值。
然后,我們再次使用recur(-2)
調用recur,並且if返回0。
然后我們print(0)
因為那是我們“輸入”的第二個值是0。
然后我們用recur(-1)
調用recur,而if(i<0)
返回0。
接下來是下一個值。
對於將來的問題,我建議您使用調試器。 例如,GDB調試器。
這就像gdb 入門 : GDB Start guid
我希望這可以幫助你。
當使用參數X >=
零調用該函數時,將執行以下行:
recur(X-1)
print X-1
recur(X-2)
return
當使用參數X <
0調用該函數時,僅執行以下行:
return
現在,如果您為每個調用級別編寫帶有一些縮進的函數調用,則會得到:
recur(2)
recur(1)
recur(0)
recur(-1)
return
print -1
recur(-2)
return
return
print 0
recur(-1)
return
return
print 1
recur(0)
recur(-1)
return
print -1
recur(-2)
return
return
return
return
除去打印件以外的所有內容,可以得到:
print -1
print 0
print 1
print -1
所以輸出是:
-1
0
1
-1
還考慮
您正在使用的變量是自動變量,因此自動變量的值受全景模型的限制,因此程序將打印控制流當前所在的寄生模型中可用的i的值
請勿執行recur(i-1)
recur(--i)
,請執行recur(i-1)
使用--i
實際上會減少i
,因此在以后的printf
它將(不正確)可見。
例如。 如果i
是0
和你recur(--i)
,它會降低實際值的i
到-1
,然后調用recur()
並且printf
將在以后打印-1
。
使用recur(i-1)
且i
為0
,將以-1
作為參數調用,但i
的實際值不會更改。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.