1、表达式与语句的区别:
运算符部分:
(1)每个运算符所需要的参与运算的操作数个数。
(2)结合性
(3)优先级
优先级 |
运算符 |
名称或含义 |
使用形式 |
结合方向 |
说明 |
---|---|---|---|---|---|
1 |
[] |
数组下标 |
数组名[常量表达式] |
左到右 | |
() |
圆括号 |
(表达式) | |||
. |
成员选择(对象) |
对象.成员名 | |||
-> |
成员选择(指针) |
对象指针->成员名 | |||
2 |
- |
负号运算符 |
-表达式 |
右到左 |
单目运算符 |
(类型) |
强制类型转换 |
(数据类型)表达式 | |||
++ |
自增运算符 |
++变量名 |
单目运算符 | ||
-- |
自减运算符 |
--变量名 |
单目运算符 | ||
* |
取值运算符 |
*指针变量 |
单目运算符 | ||
& |
取地址运算符 |
&变量名 |
单目运算符 | ||
! |
逻辑非运算符 |
!表达式 |
单目运算符 | ||
~ |
按位取反运算符 |
~表达式 |
单目运算符 | ||
sizeof |
长度运算符 |
sizeof(表达式) | |||
3 |
/ |
除 |
表达式 / 表达式 |
左到右 |
双目运算符 |
* |
乘 |
表达式*表达式 |
双目运算符 | ||
% |
余数(取模) |
整型表达式%整型表达式 |
双目运算符 | ||
4 |
+ |
加 |
表达式+表达式 |
左到右 |
双目运算符 |
- |
减 |
表达式-表达式 |
双目运算符 | ||
5 |
<< |
左移 |
变量<<表达式 |
左到右 |
双目运算符 |
>> |
右移 |
变量>>表达式 |
双目运算符 | ||
6 |
> |
大于 |
表达式>表达式 |
左到右 |
双目运算符 |
>= |
大于等于 |
表达式>=表达式 |
双目运算符 | ||
< |
小于 |
表达式<表达式 |
双目运算符 | ||
<= |
小于等于 |
表达式<=表达式 |
双目运算符 | ||
7 |
== |
等于 |
表达式==表达式 |
左到右 |
双目运算符 |
!= |
不等于 |
表达式!= 表达式 |
双目运算符 | ||
8 |
& |
按位与 |
表达式&表达式 |
左到右 |
双目运算符 |
9 |
^ |
按位异或 |
表达式^表达式 |
左到右 |
双目运算符 |
10 |
| |
按位或 |
表达式|表达式 |
左到右 |
双目运算符 |
11 |
&& |
逻辑与 |
表达式&&表达式 |
左到右 |
双目运算符 |
12 |
|| |
逻辑或 |
表达式||表达式 |
左到右 |
双目运算符 |
13 |
?: |
条件运算符 |
表达式1? 表达式2: 表达式3 |
右到左 |
三目运算符 |
14 |
= |
赋值运算符 |
变量=表达式 |
右到左 | |
/= |
除后赋值 |
变量/=表达式 | |||
*= |
乘后赋值 |
变量*=表达式 | |||
%= |
取模后赋值 |
变量%=表达式 | |||
+= |
加后赋值 |
变量+=表达式 | |||
-= |
减后赋值 |
变量-=表达式 | |||
<<= |
左移后赋值 |
变量<<=表达式 | |||
>>= |
右移后赋值 |
变量>>=表达式 | |||
&= |
按位与后赋值 |
变量&=表达式 | |||
^= |
按位异或后赋值 |
变量^=表达式 | |||
|= |
按位或后赋值 |
变量|=表达式 | |||
15 |
, |
逗号运算符 |
表达式,表达式,… |
左到右 |
|
上表中可以总结出如下规律:
- 结合方向只有三个是从右往左,其余都是从左往右。
- 所有双目运算符中只有赋值运算符的结合方向是从右往左。
- 另外两个从右往左结合的运算符也很好记,因为它们很特殊:一个是单目运算符,一个是三目运算符。
- C语言中有且只有一个三目运算符。
- 逗号运算符的优先级最低,要记住。
- 此外要记住,对于优先级:算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符。逻辑运算符中“逻辑非 !”除外。
- 运算符在前,先进行计算,再取变量的值使用。变量在前,先取变量值使用,再进行计算。
- 逻辑运算符&&:有假为假,全真为真;||:有真为真,全假为假。
- 按位与(&):相同位上有假即位假,全真为真;按位或(|):相同位上有真即为真,全假为假。
- 按位异或:相同为0,不同为1。
(4)运算符的特殊用法
1.%; 2.=与==; 3.逻辑运算符的短路特性:当逻辑&&运算左边为假时,就不会再判断右边的逻辑运算,逻辑||左边为假时,会判断右边的运算;
(5)位运算的重要意义
1.将一个操作数中第n位置1,其它位不变。num = num | 1 << n;
2.将操作数中第n位清0,其它位不变。num = num & (1 << n);
3.测试第n位:if(num & 1 << n)
4.从一个指定宽度的数中取出其中的某几位:
if(p1 <= p2)
{
temp1 = a >> (p1-1); // 将这个数右移,使得所需要的位数是从最右端开始
}
for(i=(p2-p1);i>=0;i--) // 选取p1和p2之间的这段位数
putchar(((temp1 >> i) & 1) ? '1' : '0'); // 输出这个数如果是1,则输出1,否则输出0.
printf("\n");
********一些容易出错的优先级问题*******
上表中,优先级同为1 的几种运算符如果同时出现,那怎么确定表达式的优先级呢?这是很多初学者迷糊的地方。下表就整理了这些容易出错的情况:
优先级问题 | 表达式 | 经常误认为的结果 | 实际结果 |
---|---|---|---|
. 的优先级高于 *(-> 操作符用于消除这个问题) | *p.f | p 所指对象的字段 f,等价于: (*p).f | 对 p 取 f 偏移,作为指针,然后进行解除引用操作,等价于: *(p.f) |
[] 高于 * | int *ap[] | ap 是个指向 int 数组的指针,等价于: int (*ap)[] | ap 是个元素为 int 指针的数组,等价于: int *(ap []) |
函数 () 高于 * | int *fp() | fp 是个函数指针,所指函数返回 int,等价于: int (*fp)() | fp 是个函数,返回 int*,等价于: int* ( fp() ) |
== 和 != 高于位操作 | (val & mask != 0) | (val &mask) != 0 | val & (mask != 0) |
== 和 != 高于赋值符 | c = getchar() != EOF | (c = getchar()) != EOF | c = (getchar() != EOF) |
算术运算符高于位移 运算符 | msb << 4 + lsb | (msb << 4) + lsb | msb << (4 + lsb) |
逗号运算符在所有运 算符中优先级最低 | i = 1, 2 | i = (1,2) | (i = 1), 2 |