一道递归函数,把小弟我搞糊涂了
一道递归函数,把我搞糊涂了
------解决思路----------------------
------解决思路----------------------
“给定一个小点的输入,完整单步跟踪(同时按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史)一遍。”是理解递归函数工作原理的不二法门!
递归函数关注以下几个因素
·退出条件
·参数有哪些
·返回值是什么
·局部变量有哪些
·全局变量有哪些
·何时输出
·会不会导致堆栈溢出
------解决思路----------------------
用笔画画图就能看懂了
------解决思路----------------------
递归调用与一般调用是不一样的。
函数在调用另一个函数时,会开辟空间生成调用函数栈帧和被调用函数栈帧,调用函数会push保存寄存器如eax,edx,ecx,被调用函数也会push保存寄存器到栈中,比如edi,ebx,esi,ebp,esp,所有的中间值都保存在每一个调用所对应的栈帧中。在调用结束时pop恢复这些寄存器,同时返回到之前保存的调用函数地址,这样一步步逆着原来的顺序返回。
如果是一般的函数调用,就只需恢复寄存器然后执行ret指令返回;但是在递归调用时,除了要恢复寄存器,还要执行一些含有递归意义的指令,否则只是把中间的值保存,而没有利用, 这里
的作用就是把每个保存在栈帧中的值打印出来,然后把这个值减1(n--),再次利用递归把比它小的值按同样的递归方法打印出来此处e(--n)是纯粹的重复递归,似乎意义不大。这两句其实就是你利用递归需要达成的目的。
void e(int );
main()
{
int a;
a=3;
e(a);
}
void e(int n)
{
if(n>0)
{
e(--n);
printf("%d", n);
e(--n);
}
}
------解决思路----------------------
void e(int , int, char*);
int main()
{
int a;
int count = 0;
a=3;
e(a, count, "fist time");
system("pause");
}
void printFormat(int count)
{
for (int i = 0; i < count; i++)
{
printf("\t");
}
}
void e(int n, int count, char * p)
{
printFormat(count);
printf("%s第%d层入口\n", p, count);
if(n>0)
{
count++;
e(--n, count, "before print");
printFormat(count - 1);
printf("printing第%d层值%d\n", count-1, n);
e(--n, count, "after print");
count--;
}
printFormat(count);
printf("%s第%d层出口\n", p, count);
count--;
}
------解决思路----------------------
“给定一个小点的输入,完整单步跟踪(同时按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史)一遍。”是理解递归函数工作原理的不二法门!
递归函数关注以下几个因素
·退出条件
·参数有哪些
·返回值是什么
·局部变量有哪些
·全局变量有哪些
·何时输出
·会不会导致堆栈溢出
------解决思路----------------------
用笔画画图就能看懂了
------解决思路----------------------
递归调用与一般调用是不一样的。
函数在调用另一个函数时,会开辟空间生成调用函数栈帧和被调用函数栈帧,调用函数会push保存寄存器如eax,edx,ecx,被调用函数也会push保存寄存器到栈中,比如edi,ebx,esi,ebp,esp,所有的中间值都保存在每一个调用所对应的栈帧中。在调用结束时pop恢复这些寄存器,同时返回到之前保存的调用函数地址,这样一步步逆着原来的顺序返回。
如果是一般的函数调用,就只需恢复寄存器然后执行ret指令返回;但是在递归调用时,除了要恢复寄存器,还要执行一些含有递归意义的指令,否则只是把中间的值保存,而没有利用, 这里
printf("%d", n);
e(--n);
的作用就是把每个保存在栈帧中的值打印出来,然后把这个值减1(n--),再次利用递归把比它小的值按同样的递归方法打印出来此处e(--n)是纯粹的重复递归,似乎意义不大。这两句其实就是你利用递归需要达成的目的。