C语言面试干货——C语言自增/自减操作的陷阱
Posted 从善若水
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言面试干货——C语言自增/自减操作的陷阱相关的知识,希望对你有一定的参考价值。
文章目录
本人就职于国际知名终端厂商,负责modem芯片研发。
在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。
C语言面试干货——C语言自增/自减操作的陷阱
【陷阱1】自增/自减在表达式求值中的陷阱
“预测”一下这段code的输出
#include<stdio.h>
int main(void)
{
int a,b=2;
a= b*2 + 5*(1+b++);
printf("a=%d b=%d\\n",a,b);
return 0;
}
大家肯定告诉我答案是a=19,b=3;
真的是这样吗?看一下上面这段code在我电脑上的输出
b=3没有疑问,但是为什么a=21?
(你的IDE可能运行的结果是a=19,但这不能说明在其它IDE上也能得到正确的值)
再来看这段code
#include<stdio.h>
int main(void)
{
int a,b=2;
a = b++ +b++;
printf("a=%d b=%d\\n",a,b);
return 0;
}
大家肯定又告诉我答案是a=5,b=4;
真的是这样吗?看一下上面这段code在我电脑上的输出
其实上面两段Demo的结果在C语言中都是未定义的,原因在于C编译器的设计。
C编译器在设计时为了提升效率,会自行选择先对表达式中的哪个子表达式求值。
例如在第一个Demo中的表达式 “a= b×2 + 5×(1+b++)”,编译器可能先对 “5×(1+b++)”进行求值,求值后b变成了3,然后再对“b×2”求值等于6,最后a=6+15=21;也有可能按照从左到右的顺序计算“a= b×2 + 5×(1+b++)”,这样得到的结果就是a=4+15=19
再看第二个Demo中的“a = b++ +b++”,我们自然会认为先计算左边的“b++”,再计算右边的“b++”,最后求和a=2+3=5;但是取决于编译器的设计,也可以先使用b的旧值2进行加法操作,然后对b自加两次,最后结果a=4
所以上面表达式的结果都是未定义的,取决于你使用的编译器,如果有面试官问你这样的题直接告诉他结果未定义
【陷阱2】在printf中使用自增/自减的陷阱
看下面这段code,告诉我结果是多少?
#include<stdio.h>
int main(void)
{
int a=5;
printf("a=%d a*a=%d\\n",a,a*a++);
return 0;
}
同学们自信的告诉我答案是 a=5,a×a=25;
来看一下我电脑的输出:
原理同上,编译器可以自行选择先对函数中的哪个参数求值
在这个例子中,编译器先计算右边的参数,并且在计算右边的参数时按照从右到左求值,先计算“a++”,再计算“a×a”(此时a×a中第一个a=6,第二个a=5),最后计算左边的参数a=6
其实在其它编译器下还有可能有其它的结果出现,这里不在赘述这些可能的值了(e.g. a=5 a×a=30)
【避免】上面的问题怎么避免?
- 如果一个变量出现在一个函数的多个参数中,不要对该变量使用递增或递减运算符;
- 如果一个变量多次出现在一个表达式中,不要对该变量使用递增或递减运算符。
自增/自减面试常问问题
问题1 :
#include<stdio.h>
int main(void)
{
int a,b=5;
a=b+++3;
printf("a=%d b=%d\\n",a,b);
return 0;
}
答案是: a=8 b=6
这里考察的是c语言编译器的“maximal munch strategy”特性,类似算法中的贪婪算法,编译器会将“a=b+++3;”识别为“a=b++ +3;”
问题2:
#include<stdio.h>
int main(void)
{
int a,b=5,c=6;
//a=b+++++c; //case 1:编译error
//a=b++ +++c; //case 2:编译error
//a=b+++ ++c; //case 3:编译success
a=b++ + ++c;//case 4:编译uccess
printf("a=%d b=%d c=%d\\n",a,b,c);
return 0;
}
答案是:a=12 b=6 c=7
我们要解释的是为什么case1和case2编译失败。
解释上面的问题,这几个问题必须先强调:
- 我们要肯定C语言中空格的重要性,它不是可有可无的;
- 然后我们要知道对一个右值和不可变左值进行自增操作在C语言中是不允许的。
我们上面提到了c语言编译器的“maximal munch strategy”特性,在这个特性下:
- case1中的“a=b+++++c;”被解析为“a=b++++ +c;”,但我们知道“b++”返回的值是一个右值不能使用自增操作,所以编译error;
- case2中的“a=b++ +++c;”被解析为“a=b++++ +c;”,所以编译error(如果你不相信可以将“a=b++ +++c;”改为“a=b++ +(++c);”即可编译通过),有同学疑问case3为什么编译通过了,这就是我们强调的空格的重要性“++”表示自增,而“+ +”就是两个加号。
That’s All
以上是关于C语言面试干货——C语言自增/自减操作的陷阱的主要内容,如果未能解决你的问题,请参考以下文章