C语言程序由若干条语句组成,每条语句由变量、运算符、表达式、函数调用和控制语句等构成。C语言的运算符十分丰富,所包含的内容也很广泛。表达式是由运算对象(包括常量、函数、变量)和运算符按一定规则连接起来的有意义的式子,表达式中可以包括运算符、常量变量、函数调用等,下面就介绍语句中最基本的元素:运算符和表达式。
运算符包括算术运算符、自增/自减运算符、赋值运算符及逗号运算符。
2.6.1 算术运算符
算术运算符如表2-6所示。
表2-6算术运算符
| 运算符 | 运算 | 优先级 | 例子 |
| ( ) | 圆括号 | 1 | 5/(1-3) |
| * | 乘法 | 3 | 7*3=21 |
| / | 除法 | 3 | 7/3.0=2.333,73=2 |
| % | 模除 | 3 | 7%3-1 |
| + | 加法 | 4 | 7+3=10 |
| - | 减法 | 4 | 7-3=4 |
说明:
① 模除运算是两个整数相除后取余数,要求“%”的两边必须是整型数据
例1:如果两边均为整型,则不要转换,如:5 % 3;
例2:如果两边不为整型,则要进行数据类型强制转换,如:(int)5.0 % 3;
② 若算术运算符两边均为整数,则结果仍为整数。如7/3=2,1/2=0。
③ 若参加运算的两个数中有一个数为实数,则结果为 double型。
④ 每个运算符都有一个优先级,如乘法与除法的优先级高于加法与减法
在对表达式求值时,按运算符优先级的高低次序进行,如先乘除、后加减括号可改变运算次序。若一个运算符对象两侧的运算符的优先级相同,则按规定的“结合方向”处理,算术运算符的结合方向都是“从左到右”,即“左结合性”。以后可以看到,有些运算符的结合方向为“从右到左”,即“右结合性”。
2.6.2 自增、自减运算符
自增(++)、自减运算符(--)属于单目运算符,优先级为2,结合方向为“右结合性”。
1、自增运算符(++)两种用法形式:
前缀形式:

后缀形式:

2、自减运算符(--)两种用法形式:
前缀形式:

后缀形式:

注意事项:
①只能用于整型变量、字符型变量或指针变量。
②单独作为语句使用时,用法简单,相当于 “i=i+1;” 或 “i = i-1;”语句。
③用于表达式时比较复杂,关键在于区分先计算或先取值,关键在于区分两部份的值:变量的值或自增(自减)表达式的值。
④ 运算速度快
简单用法1:
int i = 0 ;
++i;
说明:单独使用法,相当于 i=i+1;
简单用法2:
int a, i = 0 ;
a = i ++ ;
说明:用于简单表达式,“a = i++; ”相当于如下两句:① a=i; ② i=i+1; 语句执行后,a的值为0,i的值为1。
简单用法3:
int s, i = 3;
s = (++i)+(++i)+(++i);
说明:用于复杂表达式中,难以理解。(++i)+(++i)+(++i) 相当于 变量i 三次加1 ,变量 i 的值变为6,s的值最后变为18。
例2-12 编写自增运算符程序。
#include <stdio.h>
main( )
{ int i, j, k;
k=30;
i=k++; //先将k的值30赋给i,再将k值增1,此时k=31,i=30
printf(" i=%d, k=%d\n", i, k);
j=++k; //k值先增1,再将k值赋予j,此时k=32,j=32
printf("\n j=%d, k =%d\n", j, k);
}
运行结果如图2-10所示。

2.6.3 赋值运算符
赋值运算符为“=”,它为“右结合性”,优先级为14,倒数第二。
注意: ① 赋值运算符的左边一定为变量。
简单用法1:
int a, b, c;
a = b = c =1 ;
说明:上述表达式分析如下图所示,同时给多个变量赋同一个值。上述表达式有三个赋值运算符,优先级相同,结合方向从右往左,相当于如下表达式:a = ( b = ( c = 1 ) )。

简单用法2:
int a=1, b=2, c=3;
说明:在定义变量时,初始化变量。
请思考:
① 有如下语句: int a=b=c=0; 此语句错在什么地方?这个是很多初学者易犯的一个小毛病。
② 某学生在编写程序时,写出如下的语句:
int a=1, b=2, c=3, s;
s = a + b = c ;
请问:以上语句有什么语法错误?
例2-13 编写赋值运算符程序。
#include <stdio.h>
main( )
{ double k, x, y;
x=(k = 9.8)+7;
printf("k=%5.1f,\t x=%5.1f \n", k, x) ; //'\t'是跳格键,主要是为了隔开
y=k=9.8+7;
printf("k=%5.1f,\t y=%5.1f\n", k, y);
}
运行结果如图2-11所示。

图2-11 例2-13运行结果
源程序分析:
1)语句“ x=(k=9.8)+7; ”执行过程分析:
如下图所示,从左往右,扫描表达式,先执行优先级高的运算符,再执行优先级低的运算符,能计算而不影响计算结果的运算符则先算。

"k=9.8"表达式是一个赋值表达式,做了两件事:①变量k的值变为9.8,②"k=9.8"表达式的值为9.8。
执行语句“x=(k=9.8)+7;”时先将9.8赋给k,“(k =9.8)”的值为9.8,然后9.8加上7等于16.8,再赋给x,整个表达式的值为16.8。
2)语句”y=k=9.8+7;“执行过程分析:
如下图所示:“+”比“=”的优先级高,且赋值运算符的结合方向是右结合性,即自右至左。

执行语句“y=k=9.8+7;“时,由于“+”比“=”的优先级高,且赋值运算符的结合方向是右结合性,即自右至左,因此先计算“9.8+7,值为16.8,将 16.8 赋给 k,再将k的值16赋给变量y。此时,变量k和y的值均为16.8,而整个表达式的值为16.8。
2.6.4 逗号运算符
1、逗号运算符的有关概念
1)逗号运算符用于将多个表达式连接起来。
2)逗号运算符的优先级为15,最低。
3)逗号运算符的结合方向:从左往右
2、逗号运算符的格式
格式:
表达式1, 表达式2, …, 表达式n
3、逗号运算符的执行过程
其执行过程如下:先求解表达式1,再求解表达式2,以此类推,直至计算第n个表达式的值。整个逗号表达式的值为最后一个表达式的值。在很多情况下,使用逗号表达式只是想求出各个表达式的值。
4、逗号运算符使用案例
例1: x=( i=1, j=2, k=3);
执行过程如下图所示。

例2: x=i=1, j=2, k=3;
上述语句相当于:x=(i=1), j=2, k=3;
执行过程如下图所示。

注意: 赋值运算符“=”比逗号“,”的优先级高
除了上述几个运算符和表达式外,还有逻辑运算符、关系运算符以及相应的逻辑表达式和关系表达式,这些内容将在第3章中介绍。
2.6.5 位运算
所谓位运算是指对操作数以二进制位(bit)为单位进行的数据处理。每一个二进制位只能存放一位二进制数“0”或“1”,因此位运算的运算对象是一个二进制数位的集合C提供的位运算符参见表2-7
表2-7 位运算符
| 优先级 | 格式 | 运算符 | 含义 |
| ~ | 取反 | 2 | ~a |
| << | 左移n位 | 5 | a<<n |
| >> | 右移n位 | 5 | a>>n |
| & | 按位与 | 8 | a& b |
| a^b | 按位异或 | 9 | a^b |
| | | 按位或 | 10 | alb |
以上的运算中,取反运算是单目运算,其余为双目运算。运算的操作数只能是整数或字符型数据,不能为实型数据。手工进行位运算时,可先将整型或字符型数据转换成二进制数,运行结果以十进制数表示。
各种逻辑位运算符的求值规律参见表2-8
表2-8 逻辑位运算符的求值规律
| a | b | ~a | a & b | a ^ b | a l b |
| 1 | 1 | 0 | 1 | 0 | 1 |
| 1 | 0 |
| 0 | 1 | 1 |
| 0 | 1 | 1 | 0 | 1 | 1 |
| 0 | 0 |
| 0 | 0 | 0 |
从表2-8可以得出以下结论:
① ~ 运算,0变1,1变0。
② & 运算,当两个对应位均为1时,结果为1,否则为0。
③ ^ 运算,当两个对应位相同时,结果为1,否则为0。
④ | 运算,当两个对应位均为0时,结果为0,否则为1。
例如: unsigned char a=2, b=4, c=5, d=16, e=7, y;
(1)y = a & b;
计算分析如下:对于按位与运算,分两步计算如下:①先将十进制数转换为二进制数,②再进行按位与运算。
计算过程如下:

(2)y=a | b;
计算分析如下:对于按位或运算,分两步计算如下:①先将十进制数转换为二进制数,②再进行按位或运算。
计算过程如下:

(3)y=a ^ c;
计算分析如下:对于按位异或运算,分两步计算如下:①先将十进制数转换为二进制数,②再进行按位异或运算。
计算过程如下:
(4)y=a<<2;
计算分析如下:对于按位左移运算,分两步计算如下:①先将十进制数转换为二进制数,②再进行按位左移运算。
计算过程如下:

(5)y=d>>2;
计算分析如下:对于按位右移运算,分两步计算如下:①先将十进制数转换为二进制数,②再进行按位右移运算。
计算过程如下:
(6)y=~e;
计算分析如下:对于按位取反运算,分两步计算如下:①先将十进制数转换为二进制数,②再进行按位取反运算。
计算过程如下:
运算结果为:y=(1111 1000)=248
(7)y=d & e<<2
计算过程分析如下:
因为“<<”优先级高于“&”,所以,y=d & e<<2 等价于 y=d & (e<<2)
运算过程如下:
① e<<2表示使e左移两位,将二进制位左移两位,空出的位补0,计算如下:

② d & (e<<2)表示做按位与运算,计算如下:

将二进制数0001 000转换为十进制数16
所以最后“y=d & e<<2 ”运算结果为16。
位运算符实战演练(参考代码):
#include <stdio.h>
main()
{ int a=2,b=4,c=5,d=16,e=7,y;
y=d & e << 2;
printf("%d\n",y);
}