C程序两例

题目

1、下面程序的输出结果是多少

  1. #include <stdio.h>

  2. #define square2(x) ((x)*(x))

  3. int square1(int x)

  4. {

  5. return x*x;

  6. }

  7. int main(void)

  8. {

  9. int i = 1, j = 1;

  10. i = square1(++i);

  11. j = square2(++j);

  12. printf("%d %d\n", i, j);

  13. return 0;

  14. }

2、下面两个程序语法是否错误,如果错了,为什么?如果没有错,输出结果是多少?

  1. #include <stdio.h>

  2. int main(void)

  3. {

  4. int i = 1;

  5. ++i = i+++i;

  6. printf("%d\n", i);

  7. return 0;

  8. }

  9. #include <stdio.h>

  10. int main(void)

  11. {

  12. int i = 1;

  13. i++ = i+++i;

  14. printf("%d\n", i);

  15. return 0;

  16. }

分析

第一题

square1是求平方的函数,因为先执行了++i,i的值变为2,然后执行表达式i=square1(i),所以i=2*2=4

square2也是求平方的函数,但是是通过宏定义实现的。宏定义是简单的字符串替换,所以j = square2(++j),展开后的结果是j = ((++j)*(++j))。等价于:

  1. ++j;
  2. ++j;
  3. j = j*j;

结果为9

所以第一题答案是4 9

这里通过宏定义实现求平方的函数。

好处是减少了一次函数调用,在编译阶段就直接展开成了表达式,会提高程序执行效率。

缺点在于本题中的现象,容易出现错误,结果偏离了函数调用者的预期。这种情况常被叫做宏定义陷阱,也就是说很容易弄错。

第二题

第二题第一个程序语法是正确的,主要的一句是++i = i+++i,这句话实际上等效于(++i) = (i++) + i。根据C语言的语法特点,也就相当于:

  1. ++i;
  2. i=i+i;
  3. i++;

所以第一个程序的答案是5

第二个程序和第一个程序只有一点不同,++i = i+++i被改成了i++ = i+++i。这个在语法上是有问题的。

在C语言中,i++是右值,而++i是左值。所谓右值,就是可以放在一个等号表达式右边的;而左值,既可以放在右边,也可以放在等号左边并对其进行赋值。

所以++i = i+++i是可以执行的,而i++ = i+++i语法有错,编译阶段就不能通过。