今天又踩了自增自减的坑,于是开篇博客记录之。
话不多说,直接上代码:
#include <stdio.h>
int main(){
int a = 0;
printf("%d %d %d\n", a++, a++, a++);
a = 0;
printf("%d %d %d\n", ++a, ++a, ++a);
a = 0;
printf("%d %d %d\n", ++a, a++, ++a);
return 0;
}
问这段代码输出什么(其实是自己闲的无聊给自己出的题)。
想当然的写了:
2 1 0
3 2 1
3 1 1
然而除了第一条剩下两条都是错的,我们先来看正确答案:
2 1 0
3 3 3
3 1 3
为什么?
这里有两个知识点:
- 函数参数的压栈顺序和函数参数声明时的顺序是相反的
- a++ 和 ++a 的区别
函数参数的压栈顺序
void func(int a, int b, int c){
// ...
}
int main(){
func(1, 2, 3);
}
这段代码中,3最先被计算,其次是2,最后是1,在1被计算完后,才开始执行func
(进入func
的栈帧)。
这里传入的参数用常量做例子,如果是变量也是同理。
那么printf("%d %d %d\n", a++, a++, a++);
这条语句的输出是"2 1 0"也就不难理解了,因为这里的计算顺序(参数压栈顺序)是从右至左的。
自增/自减运算符的位置的区别
讲到这条就让我回忆起了被应试教育支配的恐惧。
印象中,关于自增(自减)运算符的知识点只有先增后赋值(++a),先赋值后自增(a++),以及各种奇葩题目。
那么如果按照上面的想法来解释,第二条和第三输出应该是没问题的,但其实这里还有一个知识点:
a++
会产生一个a
的值的副本常量,在本条语句结束后 a 的值自增1;而 ++a
会立刻将 a 的值自增 1。
回到上面第二条printf
语句printf("%d %d %d\n", ++a, ++a, ++a);
这里三个++a
运算完后,a
的值为3,然后被作为参数传入printf
,因此打印结果为3 3 3
。
第三条printf
语句printf("%d %d %d\n", ++a, a++, ++a);
从右至左执行,第三个++a
使a
的值自增 1,此时 a = 1
,第二个a++
语句产生一个a
的值的副本常量 1,然后 a = 2
,第一个++a
的值为 3,此时对应参数的位置为的值a 1 a
,因此打印出了3 1 3
。
总结
- 函数参数的压栈顺序和函数参数声明时的顺序是相反的
a++
产生一个a
的值的副本常量;而++a
立即将a
的值自增 1,这一点对自减运算也是同理
不是经常写博客,感觉语言组织能力和表达能力还有待提升。