陷阱目录
一、运算符的优先级问题
1.1 C语言中有哪些运算符
C语言的运算符主要有六类:算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符和杂项运算符。
算术运算符主要是进行数学运算,主要如下表
算术运算符 | 描述 |
---|---|
+ | 加法运算符 |
- | 减法运算符 |
* | 乘法运算符 |
/ | 除法运算符 |
% | 取模运算符,或者叫取余运算符 |
++ | 自加运算符 |
– | 自减运算符 |
关系运算符,主要是指用来进行比较的运算符,详细如下表:
关系运算符 | 描述 |
---|---|
== | 确定符号两边的值是否相等,是则为真,否则为假 |
!= | 确定等号两边的值是否不相等,是则为真,否则为假 |
> | 确定符号左边的值是否大于右边的,是为真,否则为假 |
< | 确定符号左边的值是否小于右边的,是为真,否则为假 |
>= | 确定符号左边的值是否大于等于右边的,是为真,否则为假 |
<= | 确定符号左边的值是否小于等于右边的,是为真,否则为假 |
逻辑运算符,主要是用来通过符号两边的操作数来确定条件的真假,如下表所示:
逻辑运算符 | 描述 |
---|---|
&& | 符号两边的操作数都为真,则表示的条件才为真,否则为假 |
|| | 符两边的操作数有一个为真,则表示的条件就为真,否则为假 |
! | 符号右边的为假,则表示的条件为真,否者为假 |
位运算符使用来对二进制数进行的操作,主要包括下表几个操作:
位运算符 | 描述 |
---|---|
& | 二进制数按位取与运算 |
| | 按位取或运算 |
^ | 按位取异或运算 |
赋值运算符是用来,将一个变量的值经过操作后赋值到另一个变量上去,详细如表所示:
赋值运算符 | 描述 |
---|---|
= | 将符号右边的值赋给左边的变量 |
+= | 将符号右边的值加上符号左边的值赋给左边的变量 |
-= | 意义类同上 |
*= | 意义类同上 |
/= | 意义类同上 |
%= | 意义类同上 |
<<= | 意义类同上 |
>>= | 意义类同上 |
&= | 意义类同上 |
|= | 意义类同上 |
^= | 意义类同上 |
其余的运算符。如下表所示:
杂项运算符 | 描述 |
---|---|
(), [], ->, . | 后缀 |
sizeof | 取变量或数据结构的字节数 |
& | 取址运算符 |
* | 解地址运算符 |
?: | 条件表达式 |
1.2 个运算符的优先级
以上几类的运算符优先级。从上到下一次递减,图下表所示:
运算符 | 结合性 |
---|---|
() [] . -> | 自左向右 |
! ~ ++ – - (type) * & sizeof | 自右向左 |
* / % | 自左向右 |
+ - | 自左向右 |
<< >> | 自左向右 |
< <= > >= | 自左向右 |
== != | 自左向右 |
& | 自左向右 |
^ | 自左向右 |
| | 自左向右 |
&& | 自左向右 |
|| | 自左向右 |
?: | 自右向左 |
所有的赋值运算符 | 自右向左 |
, | 自左向右 |
1.3 易错总结
- sizeof() 是一个运算符而不是一个函数
- 位移运算和算术运算混合:
int hi =1; // hi r的高四位 int low = 0; // low r的低四位 // 假设r是一个8位的整数,hi和low也是 int r = hi << 4 + low; // 该等式是错的,因为加法运算符的优先级高于位移运算符,所以相当于:int r= hi << (4 + low); // 正确的如下 int r = (hi << 4) + low;
逻辑运算符和按位运算符混用:
// 本来的意思是0和1进行按位与之后是否等于0,但是按下面的方式就成了1是否等于0,然后在按位与 if(0 & 1 == 0); // 正确如下 if((0 & 1) == 0);
二、条件判断语句易出中招陷阱
2.1 switch…case语句省略break后的陷阱
在switch…case语句中若是不注意省略了每一个case后的break,则程序将后紧接着运行按着的下一个case中的语句,不管是否满足条件
int flag = 2;
switch(flag){
case 1:printf("red\n");
break;
case 2:printf("green\n");
// break; //若省略掉这个break则将会输出:green和blue
case 3:printf("blue\n")
break;
}
2.2 else带来的陷阱
if…else…语句是C语言编程中常用的判断语句,常常会因为省略掉“{}”,而导致很难排查的错误
if(flag == 0)
if(x ==0) printf("no data\n"); // 这里出错
else{
int y = x / flag;
return y;
}
上述判断中是为了避免除数flag为0而做出的判断,但是由于第一个if语句没有加大括号,是编译器误认else语句是第二个if的else,整理一下就清晰了:
if(flag == 0)
if(x ==0) printf("no data\n"); // 这里出错
else{
int y = x / flag;
return y;
}
因此为了避免这种错误,就不要为了怕麻烦,而省略掉大括号了,上述代码正确如下:
if(flag == 0){
if(x ==0) printf("no data\n");
}// 加上大括号
else{
int y = x / flag;
return y;
}