递归函数与栈

递归函数与栈

关于函数调用与栈的关系:链接
下面是在函数调用与栈的关系的基础上,为了解递归调用的笔记。

  为了方便描述,将一个函数f(x)的栈帧以下图的方式进行简化:
在这里插入图片描述
并用一个求阶乘的函数来解释递归函数与栈的联系:

int fun(int N)
{
    if(N == 1) return 1;
    return N*fun(N-1);
}

int main(int argc, char **argv)
{
    fun(3); // 为了方便描述,只求1~3的阶乘
    return 0;
}

递归过程

  首先程序从主函数开始,第一个压入的是主程序的栈帧。每个程序(函数)都会有自己的栈帧,主程序当然是不会例外的,况且主程序也是由另一个程序所调用的(比如shell)。此时栈中的情况:
在这里插入图片描述

  在运行主程序时,需要调用fun函数,参数为3,此时就需要压入参数为3的fun函数的栈帧。栈中情况如下:
在这里插入图片描述

  当运行fun(3)时,由于N不等于1,因此需要在fun(3)中调用fun(3-1)即fun(2),此时需要再压入参数为2的fun函数。栈中情况如下:
在这里插入图片描述

  此时运行fun(2),但是fun(2)的参数N=2仍然不等于1,因此需要在fun(2)中调用fun(2-1)即fun(1),此时需要再压入参数为1的fun函数。栈中情况如下:
在这里插入图片描述

  这时运行的fun(1)的参数N=1满足了等于1的条件,因此不用再调用自己了。fun(1)返回1(该返回值在%eax寄存器中)并将其栈帧弹出恢复到fun(2)调用fun(1)时的状态:
在这里插入图片描述

  fun(2)通过寄存器%eax中的值(即fun(1)的返回值),计算出Nfun(N-1)为2,并将该值保存在%eax作为返回值。最后同样弹出自己的栈帧恢复到fun(3)调用fun(2)时的状态:
在这里插入图片描述
  同理,fun(3)通过fun(2)的返回值计算出N
fun(N-1)为6,并将该值保存在%eax作为返回值。最后弹出自己的栈帧恢复到main函数调用fun(3)时的状态:
在这里插入图片描述
  最后main函数也运行完了,将返回值0返回给某一个程序(如常见的shell)并弹出自己的栈帧:
在这里插入图片描述

最后

  从上面也就可以理解,无穷的递归也只能存在于逻辑之中。如果没有基线条件(即N == 1),栈就会不断地被栈帧填压,最后必然会导致内存不足。避免过深的递归也是同样的道理。

基线条件指的是停止递归的条件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值