由求值顺序所带来的问题

来源:互联网 发布:淘宝客佣金40 亏本了 编辑:程序博客网 时间:2024/05/01 04:56

因为近来想重新系统地学一下C,网友有推荐《c专家编程》,只可惜图书馆死活找不到,找书的过程中看到了这本

《c primer plus》,真的是很不错的书籍,在这里强烈推荐,呵呵,因为看过之后很多东西你不仅仅知其然还会知其所以然,虽然这本书我还没看完,当然最重要的还是要多练练手。呵呵,我最近就在各个论坛上疯狂找有错的代码,然后又会发现这些知识点在该书上其实已经提到过了,不过当初改的时候不一定会想得到,呵呵越来越喜欢这本书。

 

今天看到了这样一段代码,

#include <stdio.h>
#include <conio.h>
long factorial(int a)
{
    if(a>1)
      return  a*factorial(a--);
 

    else if(a==0||a==1) return 1;
    else return -1; 
}
void main()
{
      int n;
      printf("Please input a number:/n");
      scanf("%d",&n);
      printf("%d!=%ld",n,factorial(n));
    
}

提问者说这段代码看不到执行结果,黑屏一闪而过,我在VC中运行是没有执行结果显示,单步运行了下发现 a*factorial(a--); 出现了个死循环,因为调用函数时是先把a值赋过去,再自减的,也即调用时a的值没有发生过变化,于是递归不能跳出。我猜系统是对递归的嵌套层次有一定规定的,所以最后自动跳了出来,可是仔细想想也感觉不对,呵呵,这方面还得继续看才行。知道了症结所在于是我把它改成了--a,呵呵,结果却变成了(n-1)!前面百思不得其解,明明改对了啊,呵呵,调试时终于发现了问题,那便是求值的顺序问题。

 

在C中,编译器可以选择先计算一个顺序点之前哪个数的值。这个自由提高了编译器的效率,但是如果在函数参数或表达式中使用了增量运算符就会带来麻烦,因为编译器可能不以你想象中的顺序来执行,就像这个程序,编译器是先计算函数里--a,这样改过之后的语句

            return  a*factorial(a--);

其实等价于

            return  (a-1)*factorial(a-1);

于是也就不难理解后来的结果变成了(n-1)!

 

所以最终的结果应该是 return  a*factorial(a-1);

 

可以通过使用如下原则,来避免出现这种问题:

(1)如果一个变量出现在同一个函数的多个参数中时,不要将增量或减量运算符用于它上面。

(2)当一个变量多次出现在一个表达式里时,不要将增量或减量运算符运用到它的上面。

 

上面这段话就是《c prime plus》里面的,当时看着感觉很有理,呵呵,还是没得练手来的感觉深刻啊,希望以后自己能一眼看出这种错误,当然了,也不要犯这种错误啦!