递归使用,潜在问题

题记:

         本篇文章由一个“有问题”的程序,带入你进入递归的世界。虽然只是采用了递归中最简单的类型,尾递归。但却能使你马上感受到递归的妙用和烦恼。希望大家由浅入深、循序渐进,更好的使用递归。其中又涉及了递减运算符的使用,它同样是让你欢喜让你忧!虽然使用它给你带来高效的代码,但不小心同样让你深陷泥潭。

1.      #include <stdio.h>

2.      long fun(int );

3.      int i=1,j=3;        //i,j仅仅是为了说明递归时是第几级调用

4.     

5.      int main(void)

6.      {

7.               int n=3;    //测试数据较小,为了能说明问题,大了也无妨(勿溢出)

8.               printf ("3!/n");

9.               printf ("/nn=%d/n",fun(n));

10.             return 0;

11.   }

12.  

13.   long fun(int m)

14.   {

15.             long ans;

16.            

17.             if (m>0)

18.             {

19.  

20.                      printf ("Level:%d      m=%d,m:location %p/n",i++,m,&m);

21.  

22.                      //static int *p=&m;          //用于说明后缀递减运算时的问题     

23.                      //printf ("%d/n/n",*p);    //用于说明后缀递减运算时的问题

24.                     

25.                      ans=fun(m-1)*m;     //测试行

26.                     

27.                      //1.Right:ans=fun(m-1)*m;

28.  

29.                      //2.Error:ans=fun(m=m-1)*m;

30.                      //3.Error:ans=m*fun(m=m-1);

31.                      //4.Error:ans=fun(--m)*m;

32.  

33.                      //5.Error:ans=fun(m--)*m;

34.  

35.                      printf ("Return:        Level:%d  m=%d,m:location %p/n",j--,m,&m);       

36.                                        

37.             }

38.             else

39.             {       

40.                      ans=1;

41.             }

42.             return ans;

43.   }

                                               尝试分析5个可测选项会输出什么结果?

#1正确,依次调用、返回。最终效果为:fun(0)*5*4*3*2*1

 

#2/3/4表达式虽略有差异,但副作用相同,动作发生时间相同。

         貌似可以产生正确结果但运行却发现“n=0”,Why?发生了什么?这就要从递归的原理考虑,并对比#1的形式。如果是#1,在一级调用fun(mainfun的调用),即fun(3),然后这个函数调用还没执行完,就执行了fun(2) 『自身调用,funfun,和#1一样,但同时它把m的值改变了!』效果如上文所示

         如果采用#2的形式,效果:fun(0)*4*3*2*1*0,所以“n=0

 

#5是最复杂的,同时难于理解,最好能了解递归的细节、副操作、顺序点等知识(在文章最后,有简略解释)

         一级调用fun(),fun(3),注意传递给fun函数时,m就是3,而二级调用(调用自身)时,m的值还没改变呢(后缀递减)!又是fun(3)。三级调用也将是fun(3)……       递归虽然有条件检测语句(17)用于结束递归,但m相当于不变,一直递归,知道资源耗竭为止!

 

         是否有疑问呢?为什么要说“相当于”呢?如果你够细心,肯定发现了一点蛛丝马迹!

m值其实变了,但什么时候变了?以二级调用为例解释,即第一次自身调用时。fun函数调用时m给了它,随后m变成了,这可以通过加入2223行代码加以验证,你会发现m确实变成了2。那三级调用不就是fun(2)了吗?不是!!

         递归是个很奇妙的东西!它总能迷惑你的双眼。

         每一级函数调用都有自己的变量!m非彼m,可以从地址中发现(我在这个实例已经加入了显示地址的语句)。

         如果两个不同的函数,可能我们很容易的就明白,两个m的不同

如:

         fun1(int m)

         {

                   m+=3;

                   printf (“%d”,m);

         }

         fun2(int m)

         {

                   printf (“%d”,m);

         }

但换到递归,我们可能就摸不到头绪了。在此建议大家多联系多思考,语言是由基本要素扩充扩展而来。如递归不过是函数调用自身,那么函数具有的特性,它也应该具有!

 

         递减运算符在这个程序给你带来的trouble够大吗?所以用之勿慎!c就是这样,够灵活以致可以够高效、够强大;灵活又使我们摔倒千次。

 

决定命运的关键

                                               立即行动

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值