大家好,我很难理解递归函数调用,当我认为我理解它们时,我看到一个让我意识到我错了的问题 我无法理解程序的流程
#include <stdio.h>
void fun(int n)
{
if(n>0)
{
fun(--n);
printf("%d\n",n);
fun(--n);
}
}
int main(void) {
int a;
a=3;
fun(a);
return 0;
}
答案 0 :(得分:2)
当n = 3
时,这是函数的函数调用f(3)
.f(2) [1]
..f(1) [1]
...f(0) [1]
...Print 0
...f(-1) [2]
..Print 1
..f(0) [2]
.Print 2
.f(1) [2]
..f(0) [1]
..Print 0
..f(-1)[2]
其中.
表示堆栈的深度,1和2指定它是从循环中的第一次递归调用还是第二次。
由于
f(3)
变为
f(2)
print 2
f(1)
其中的内容变为
f(1)
print 1
f(0)
print 2
f(0)
print 0
f(-1)
最终成为
f(0)
print 0
f(-1)
print 1
f(0)
print 2
f(0)
print 0
f(-1)
在f(n)
n <= 0
print 0
print 1
print 2
print 0
答案 1 :(得分:1)
我认为混淆的原因是你假设同样的&#34; n&#34;每次调用函数fun()
时都会使用它。事实上,情况并非如此,因为在C语言中,参数是按值传递的。也就是说,当fun(3)
调用fun(2)
时,会创建一个新的n
- 特定于fun(2)
的一个实例。因此,在fun(3)
内调用fun(2)
后,n
的值为2,而不是-1。
你应该期待......
有趣(1)打印0
有趣(2)打印1
有趣(3)打印2
fun(1)(从第二次调用fun(2)调用)打印0
那就是它。
答案 2 :(得分:1)
让我们尝试用案例n=2
来理解它,然后你应该能够概括。
fun (2):
内部发生了什么(流程):
1)n=2:
if(n>0)
为真,fun(--n)
被调用,n
设置为值1,原因是 - ; (见下面的步骤)。
2)n=1:
现在n=1
:再次if(n>0)
为真,fun(--n)
与n=0
一起调用。见下面的步骤。
3)n=0:
现在n=0;
if(n>0)
是假的,所以我们回来了。
我认为这是你的困惑。从第3步开始,将被抛回
在第2步(不是第1步)。在fun(--n)
调用后,您实际上在步骤2中被抛出 - 因此,printf
的值为n=0
,因为减少而被调用。
然后再次在同一个地方(printf
之后)fun(--n)
被调用值n=-1
但是,它也会退出 - 最终你将被抛出开头。
答案 3 :(得分:1)
我会画一个&#34;呼叫树&#34;帮助可视化该计划。
该功能有那些部分
decrement n, call, print, decrement n, call
现在你可以画出这个:
0 -1
1->0, print 0, 0->-1, 0
2->1, print 1, 1->0, 1->0, .....
3->2, print 2, 2->1, .....
从左下角开始,每次通话都上一行。程序从左到右执行,您可以清楚地看到打印数字的顺序。
答案 4 :(得分:1)
以下是发生的事情(伪代码):
n = 3
fun(3);
n = 2
fun(2); // first fun(--n)
n = 1
fun(1); // first fun(--n)
n = 0
fun(0); // first fun(--n)
return;
print 0
n = -1
fun(-1); // second fun(--n)
return;
return;
print 1
n = 0
fun(0); // second fun(--n)
return;
return;
print 2
n = 1
fun(1); // second fun(--n)
n = 0
fun(0); // first fun(--n)
return;
print 0
n = -1
fun(-1); // second fun(--n)
return;
return;
return;
return;
答案 5 :(得分:0)
通过迭代扩展函数调用和删除条件,可以理解程序的输出;以伪代码的方式,这可以如下完成。
fun(3)
可以扩展到以下内容。
if(3>0)
{
fun(2);
printf("%d\n",2);
fun(1);
}
在以下步骤中,如果if
条件评估为false,则省略{。}}条件。
fun(1);
printf("%d\n",1);
fun(0);
printf("%d\n",2);
fun(0);
printf("%d\n",0);
fun(-1);
可以省略对具有非正参数的fun
的调用,因为它们不会生成任何输出。
fun(1);
printf("%d\n",1);
printf("%d\n",2);
printf("%d\n",0);
进一步扩展产生以下顺序。
fun(0);
printf("%d\n",0);
fun(-1);
printf("%d\n",1);
printf("%d\n",2);
printf("%d\n",0);
这可以再次简化为以下顺序。
printf("%d\n",0);
printf("%d\n",1);
printf("%d\n",2);
printf("%d\n",0);
总的来说,输出结果如下。
0
1
2
0
我希望这能回答你的问题;但是,它没有提供描述生成输出的直观方式。
答案 6 :(得分:0)
要了解递归流程,您可以使用如下所示的少量printfs来检测代码。这将显示使用缩进的函数流程序列。
#include <stdio.h>
void printSpace(int num)
{
while(num > 0)
{
printf(" ");
num--;
}
}
int NumSpace = 0;
void fun(int n)
{
printSpace(NumSpace);
printf("fun(%d)\n", n);
NumSpace += 4;
if(n>0)
{
fun(--n);
printSpace(NumSpace);
printf("%d\n",n);
fun(--n);
}
NumSpace -= 4;
}
int main(void) {
int a;
a=3;
fun(a);
return 0;
}
Result:
fun(3)
fun(2)
fun(1)
fun(0)
0
fun(-1)
1
fun(0)
2
fun(1)
fun(0)
0
fun(-1)
希望这有帮助。
答案 7 :(得分:0)
尽可能避免使用递归代码。正如您通过这个简单的示例所看到的,理解程序的流程可能很难。想象一下,在一个非常复杂的代码中找到错误是什么感觉。 对于那些认为值得投票的人来说......在用C编码的20年中,我发现很少有真正需要它的场合。