-3

我真的无法理解这段代码。当一个函数调用自己时,真正发生了什么?它与堆栈的概念有关,我知道,但我仍然无法解决这些问题。

#include<stdio.h>

fun(int);

main()
{
  int x=3;
  fun(x);
}

fun(int a) 
{
  if(a<0)
   {
     fun(--a);    // what happens when function calls itself
     printf("%d",a);
     fun(--a);
   }
} 

请解释在此期间发生的事件顺序。

4

3 回答 3

4

在这种情况下,调用 fun() 就像调用任何其他函数一样。例如:

int main() {
   int a = 0;
   foo(a);
   printf("main a = %d\n", a);
}

void foo(int a) {
   a = 1;
   bar(a);
   printf("foo a = %d\n", a);
}

void bar(int a) {
   a = 2;
   printf("bar a = %d\n", a);
}

您的调用顺序如下所示:

main();
foo();
bar();

你的输出将是这样的:

bar a = 2
foo a = 1
main a = 0

参数是按值传递的,因此a复制的,实际上是每个函数中的不同变量。递归也是如此。

main();  x = 3
fun(3);  a = 3, so a > 0, nothing happens, return to main()

如果您要更改条件,那么 fun() 在 a > 0 时调用自身(自上而下阅读)

main();  x = 3
fun(3);  a = 3, a > 0 so --a = 2, fun(2)
fun(2);  a = 2, a > 0 so --a = 1, fun(1)
fun(1);  a = 1, a > 0 so --a = 0, fun(0)
fun(0);  a = 0, so return to fun(1)

fun(1);  printf("%d", a) displays 1, --a = 0, fun(0)  /* same as fun(1) above */
fun(0);  a = 0, so return to fun(1)

fun(1);  nothing left to do so return to fun(2)       /* same as fun(1) above */

fun(2);  printf("%d", a) displays 2, --a = 1, fun(1)
fun(1);  a = 1, a > 0 so --a = 0, fun(0)              /* this is a new fun(1) */
fun(0);  a = 0, so return to fun(1)

fun(1);  printf("%d", a) displays 1, --a = 0, fun(0)
fun(0);  a = 0, so return to fun(1)

fun(1);  nothing left to do so return to fun(2)

fun(2);  nothing left to do so return to fun(3)

fun(3);  printf("%d", a) displays 3, --a = 2, fun(2)  /* halfway point */
fun(2);  a = 2, a > 0 so --a = 1, fun(1)
fun(1);  a = 1, a > 0 so --a = 0, fun(0)
fun(0);  a = 0, so return to fun(1)

fun(1);  printf("%d", a) displays 1, --a = 0, fun(0)
fun(0);  a = 0, so return to fun(1)

fun(1);  nothing left to do so return to fun(2)

fun(2);  printf("%d", a) displays 2, --a = 1, fun(1)
fun(1);  a = 1, a > 0 so --a = 0, fun(0)
fun(0);  a = 0, so return to fun(1)

fun(1);  printf("%d", a) displays 1, --a = 0, fun(0)
fun(0);  a = 0, so return to fun(1)

fun(1);  nothing left to do so return to fun(2)

fun(2);  nothing left to do so return to fun(3)

fun(3);  nothing left to do so return to main()

你的输出应该是: 1213121 它反映了调用的树结构:

        3
       / \
      /   \
     2     2
    / \   / \
   1   1 1   1
于 2012-08-01T13:24:49.400 回答
1

函数参数在 C 中按值传递,这意味着每次调用函数时都会创建临时局部变量。当一个函数被递归调用时,每次都会创建一组新的变量。但是,递归不一定会节省存储空间,因为必须在某个地方维护正在处理的值的堆栈。

于 2012-08-01T12:50:22.993 回答
0

函数只是驻留在内存某处的代码。每当您进行函数调用时,编译器都会将其转换为平台的汇编代码命令,该命令保存函数调用完成后要执行的下一个命令的地址,并告诉处理器在内存中“跳转”的位置为了读取下一个要执行的命令。

递归之所以有效,是因为您可以轻松地告诉处理器“跳”回内存中函数代码块的开头。您正在调用的当前函数与任何其他函数一样具有内存地址,因此处理器跳转到内存中当前函数代码块的开头或内存中某个其他函数代码块的开头没有区别。

堆栈之所以起作用,是因为我们需要保存完成函数调用后要执行的命令的返回地址,以及存储当前函数参数和自动变量的位置。因此,当您进行连续的函数调用时,会创建一个调用堆栈,如果堆栈向下增长,则会创建参数以及堆栈上任何先前调用的函数的返回地址。这统称为函数的“堆栈帧”。从函数返回时,当前函数的栈帧从栈底弹出,然后读取并执行函数完成后处理器需要跳回的内存地址。在递归的情况下,

于 2012-08-01T12:59:58.177 回答