什么是运算符 ?
运算符是应用于 C 变量和其他对象时触发操作的符号。运算符作用的数据项称为操作数。
C语言中运算符和表达式数量之多,在高级语言中是少见的。正是丰富的运算符和表达式使C语言功能十分完善。这也是C语言的主要特点之一。
C语言的运算符不仅具有不同的优先级,而且还有一个特点,就是它的结合性。在表达式中,各运算量参与运算的先后顺序不仅要遵守运算符优先级别的规定,还要受运算符结合性的制约,以便确定是自左向右进行运算还是自右向左进行运算。这种结合性是其它高级语言的运算符所没有的,因此也增加了C语言的复杂性。
根据运算符可以作用的操作数,可以将运算符分类如下:
**一元运算符:(Unary) **那些只需要对单个操作数执行操作的运算符称为一元运算符。例如增量和减量运算符
**二进制运算符:**那些需要两个操作数才能操作的运算符称为二进制运算符。二进制运算符分为:
-
-
- 算术运算符 – 用于各类数值运算。包括加(+)、减(-)、乘(*)、除(/)、求余(或称模运算,%)、自增(++)、自减(–)共七种
- 关系运算符 – 用于比较运算。包括大于(>)、小于(<)、等于(==)、 大于等于(>=)、小于等于(<=)和不等于(!=)六种
- 逻辑运算符 – 用于逻辑运算。包括与(&&)、或(||)、非(!)三种
- 赋值运算符 – 用于赋值运算,分为简单赋值(=)、复合算术赋值(+=,-=,*=,/=,%=)和复合位运算赋值(&=,|=,^=,>>=,<<=)三类共十一种。
- 条件运算符- 这是一个三目运算符,用于条件求值(?:)。
- 逗号运算符:用于把若干表达式组合成一个表达式(,)
- 指针运算符:用于取内容(*)和取地址(&)二种运算
- 求字节数运算符:用于计算数据类型所占的字节数(sizeof)
- 位运算符 参与运算的量,按二进制位进行运算。包括位与(&)、位或(|)、位非(~)、位异或(^)、左移(<<)、右移(>>)六种
- 特殊运算符:有括号(),下标[],成员(→,.)等几种
- 杂项运算符
-
算术运算符
算术运算符用于执行数学计算,例如加法(+),减法(-),乘法(*),除法(/)和取模运算(%)。
Operator | Description |
---|---|
+ | Addition (加) |
– | Subtraction (减) |
* | Multiplication (乘) |
/ | Division (除) |
% | Modulus (取余数) |
- 加法运算符“+”:加法运算符为双目运算符,即应有两个量参与加法运算。如 a+b,4+8等。具有右结合性。
- 减法运算符“-”:减法运算符为双目运算符。但“-”也可作负值运算符,此时为单目运算,如-x,-5 等具有左结合性。
- 乘法运算符“*”:双目运算,具有左结合性。
- 除法运算符“/”:双目运算具有左结合性。参与运算量均为整型时,结果也为整型,舍去小数。如果运算量中有一个是实型,则结果为双精度实型。
- 求余运算符(模运算符)“%”:双目运算,具有左结合性。要求参与运算的量均为整型。求余运算的结果等于两数相除后的余数。
算术表达式和运算符的优先级和结合性
表达式是由常量、变量、函数和运算符组合起来的式子。一个表达式有一个值及其类型,它们等于计算表达式所得结果的值和类型。表达式求值按运算符的优先级和结合性规定的顺序进行。单个的常量、变量、函数可以看作是表达式的特例。算术表达式是由算术运算符和括号连接起来的式子。
算术表达式 –用算术运算符和括号将运算对象(也称操作数)连接起来的、符合 C 语法规则的式子。
以下是算术表达式的例子:
a+b
(a*2)/c
(x+r)*8-(a+b)/7
++I
sin(x)+sin(y)
(++i)-(j++)+(k–)
运算符的优先级:C语言中,运算符的运算优先级共分为 15 级。1 级最高,15 级最低。在表达式中,优先级较高的先于优先级较低的进行运算。而在一个运算量两侧的运算符优先级相同时,则按运算符的结合性所规定的结合方向处理。
运算符的结合性:C语言中各运算符的结合性分为两种,即左结合性(自左至右)和右结合性(自右至左)。例如算术运算符的结合性是自左至右,即先左后右。如有表达式 x-y+z,则 y 应先与“-”号结合,执行 x-y 运算,然后再执行+z 的运算。这种自左至右的结合方向就称为“左结合性”。而自右至左的结合方向称为“右结合性”。
最典型的右结合性运算符是赋值运算符。如 x=y=z,由于“=”的右结合性,应先执行 y=z 再执行 x=(y=z)运算。
C语言运算符中有不少为右结合性,应注意区别,以避免理解错误。
强制类型转换运算符 – 其一般形式为:
(类型说明符) (表达式)
其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。
例如:
- (float) a 把 a 转换为实型
- (int)(x+y) 把 x+y 的结果转换为整型
自增、自减运算符
自增1,自减1运算符:自增 1 运算符记为“++”,其功能是使变量的值自增 1。自减 1 运算符记为“–”,其功能是使变量值自减 1。
自增 1,自减 1 运算符均为单目运算,都具有右结合性。可有以下几种形式:
- ++i i 自增 1 后再参与其它运算。在使用i之前,先使i的值加1,如果i的原值为3,则执行j=++i后,j的值为4。
- –i i 自减 1 后再参与其它运算。在使用i之前,先使i的值减1,如果i的原值为3,则执行j=–i后,j的值为2
- i++ i 参与运算后,i 的值再自增 1。在使用i之后,使i的值加1,如果i的原值为3,则执行j=i++后,j的值为3,然后i变为4
- i– i 参与运算后,i 的值再自减 1。在使用i之后,使i的值减1,如果i的原值为3,则执行j=i–后,j的值为3,然后i变为2
在理解和使用上容易出错的是 i++和 i–。 特别是当它们出在较复杂的表达式或语句中时,常常难于弄清,因此应仔细分析。
++i是先执行i=i+1后,再使用i的值;而i++是先使用i的值后,再执行i=i+1。
正确地使用++和–,可以使程序简洁、清晰、高效。请注意:
- 自增运算符(++)和自减运算符(–)只能用于变量,而不能用于常量或表达式。
- ++和–的结合方向是“自右至左”。
- 自增运算符(++)和自减运算符(–)使用十分灵活,但在很多情况下可能出现歧义性,产生“意想不到”的副作用。
- 自增(减)运算符在C程序中是经常见到的,常用于循环语句中,使循环变量自动加1。也用于指针变量,使指针指向下一个地址。
例一:
main(){ int i=8; printf("%d\n",++i); printf("%d\n",--i); printf("%d\n",i++); printf("%d\n",i--); printf("%d\n",-i++); printf("%d\n",-i--); }
的初值为 8,第 2 行 i 加 1 后输出故为 9;第 3 行减 1 后输出故为 8;第 4 行输出 i 为8 之后再加 1(为 9);第 5 行输出 i 为 9 之后再减 1(为 8) ;第 6 行输出-8 之后再加 1(为 9),第 7 行输出-9 之后再减 1(为 8)。
例二
main() { int i=5,j=5,p,q; p=(i++)+(i++)+(i++); q=(++j)+(++j)+(++j); printf("%d,%d,%d,%d",p,q,i,j); }
这个程序中,对 P=(i++)+(i++)+(i++)应理解为5+6+7相加,故 P 值为 18。最后的i++不参与运算。然后 i 再自增 1三次相当于加 3 故 i 的最后值为 8。
而对于 q 的值则不然,q=(++j)+(++j)+(++j)应理解为 6+7+8,这个数值应该是21. 但是结果是22. 这是编译器的问题,是程序的副作用。详情请看:
程序副作用和求值顺序点
例三表示了j的正确值。 j 的最后值仍为 8。
例三 q=(++j)+(++j)+(++j)
main() { int j=5,p,q,r; p=(++j); printf("%d\n",p); q=p+(++j); printf("%d\n",q); r=q+(++j); printf("%d\n",r); }
关系运算符 (Relational Operators)
关系运算符用于比较两个数量或值。
Operator | Description |
---|---|
== | Is equal to (等于) |
!= | Is not equal to (不等于) |
> | Greater than (大于) |
< | Less than (小于) |
>= | Greater than or equal to (大于等于) |
<= | Less than or equal to (小于等于)
|
逻辑运算符 (Logical Operators)
当我们测试多个条件以做出决策时,C提供了三个逻辑运算符。 它们是:&&(表示逻辑AND),||。 (表示逻辑OR)和! (表示逻辑非)。
Operator | Description |
---|---|
&& | And 逻辑与运算符 – 两个表达式的逻辑结合,如果两个表达式的结果均为True(真),则结果为True(真)。如果两个表达式的任何一个结果为False(假),则结果为False(假) |
|| | Or 逻辑或运算符 – – 两个表达式的逻辑结合,如果任何一个表达式的结果为True(真),则结果为True(真)。如果两个表达式的结果均为False(假),则结果为False(假) |
! | Not 逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 |
与运算符&&和或运算符||均为双目运算符。具有左结合性。非运算符!为单目运算符,具有右结合性。逻辑运算符和其它运算符优先级的关系可表示如下:
按照运算符的优先顺序可以得出:
a>b && c>d 等价于 (a>b)&&(c>d)
!b==c||d<a 等价于 ((!b)==c)||(d<a)
a+b>c&&x+y<b 等价于 ((a+b)>c)&&((x+y)<b)
但为了使你的程序容易被理解,成为较好的程序员。建议改用括号的时候还是要用括号。
逻辑运算的值
逻辑运算的值也为“真”和“假”两种,用“1”和“0 ”来表示。其求值规则如下:
- 与运算 &&:参与运算的两个量都为真时,结果才为真,否则为假。
例如:
5>0 && 4>2
由于 5>0 为真,4>2 也为真,相与的结果也为真。
- 或运算||:参与运算的两个量只要有一个为真,结果就为真。 两个量都为假时,结果为假。
例如:
5>0||5>8
由于 5>0 为真,相或的结果也就为真。
- 非运算!:参与运算量为真时,结果为假;参与运算量为假时,结果为真。
例如:
!(5>0) 的结果为假。
虽然C编译在给出逻辑运算值时,以“1”代表“真”,“0 ”代表“假”。 但反过来在判断一个量是为“真”还是为“假”时,以“0”代表“假”,以非“0”的数值作为“真”。例如:
由于 5 和 3 均为非“0”因此 5&&3 的值为“真”,即为 1。
又如:
5||0 的值为“真”,即为 1。
逻辑表达式
逻辑表达式的一般形式为:
表达式 逻辑运算符 表达式
其中的表达式可以又是逻辑表达式,从而组成了嵌套的情形。
例如:
(a&&b)&&c
根据逻辑运算符的左结合性,上式也可写为:
a&&b&&c
逻辑表达式的值是式中各种逻辑运算的最后值,以“1”和“0”分别代表“真”和“假”。
赋值运算符
赋值运算符用于把表达式的结果赋予变量。下表列出了 C 语言支持的赋值运算符:
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C = A + B 将把 A + B 的值赋给 C |
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A |
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C – A |
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C *= A 相当于 C = C * A |
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A |
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A |
<<= | 左移且赋值运算符 | C <<= 2 等同于 C = C << 2 |
>>= | 右移且赋值运算符 | C >>= 2 等同于 C = C >> 2 |
&= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 |
^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 |
|= | 按位或且赋值运算符 | C |= 2 等同于 C = C | 2 |
赋值运算符和赋值表达式
简单赋值运算符
简单赋值运算符和表达式:简单赋值运算符记为“=”。由“= ”连接的式子称为赋值表达式。其一般形式为:
变量=表达式
例如:
x=a+b
w=sin(a)+sin(b)
y=i+++–j
赋值表达式的功能是计算表达式的值再赋予左边的变量。赋值运算符具有右结合性。因此
a=b=c=5
可理解为
a=(b=(c=5))
在其它高级语言中,赋值构成了一个语句,称为赋值语句。 而在 C 中,把“=”定义为运算符,从而组成赋值表达式。 凡是表达式可以出现的地方均可出现赋值表达式。
例如,式子:
x=(a=5)+(b=8)
是合法的。它的意义是把 5 赋予 a,8 赋予 b,再把 a,b 相加,和赋予 x,故 x 应等于 13。
在C语言中也可以组成赋值语句,按照C语言规定,任何表达式在其未尾加上分号就构成为语句。因此如
x=8;
a=b=c=5;
都是赋值语句,在前面各例中我们已大量使用过了。
复合的赋值运算符
在赋值符“ = ”之前加上其它二目运算符可构成复合赋值符。如 +=,-=,*=, /=,%=,<<=,>>=,&=,^=,|=。
构成复合赋值表达式的一般形式为:
变量 双目运算符=表达式
它等效于:
变量=变量 运算符 表达式
例如:
a+=5 等价于 a=a+5
x*=y+7 等价于 x=x*(y+7)
r%=p 等价于 r=r%p
复合赋值符这种写法,对初学者可能不习惯,但十分有利于编译处理,能提高编译效率并产生质量较高的目标代码。
例四:
#include <stdio.h> void main() { int a = 21; int c ; c = a; printf("Line 1 - = operator, c-value = %d\n", c ); c += a; printf("Line 2 - += operator, c-value = %d\n", c ); c -= a; printf("Line 3 - -= operator, c-value = %d\n", c ); c *= a; printf("Line 4 - *= operator, c-value = %d\n", c ); c /= a; printf("Line 5 - /= operator, c-value = %d\n", c ); c = 200; c %= a; printf("Line 6 - %= operator, c-value = %d\n", c ); c <<= 2; printf("Line 7 - <<= operator, c-value = %d\n", c ); c >>= 2; printf("Line 8 - >>= operator, c-value = %d\n", c ); c &= 2; printf("Line 9 - &= operator, c-value = %d\n", c ); c ^= 2; printf("Line 10 - ^= operator, c-value = %d\n", c ); c |= 2; printf("Line 11 - |= operator, c-value = %d\n", c ); }
逗号运算符和逗号表达式
在C语言中逗号“,”也是一种运算符,称为逗号运算符。 其功能是把两个表达式连接起来组成一个表达式, 称为逗号表达式。
其一般形式为:
表达式 1,表达式 2
其求值过程是分别求两个表达式的值,并以表达式 2 的值作为整个逗号表达式的值。
例五:
main() { int a=2,b=4,c=6,x,y; y=(x=a+b); printf("y=%d,x=%d",y,x); }
运算符的优先权
下列运算符优先权顺序决定程序的执行顺序
Operator(s) | Category | Description |
---|---|---|
! | Unary | Logical not; associativity goes right to left |
++ — | Unary | Increment, decrement, read from right to left |
* / % | Math | Multiplication, division, modulo |
+ – | Math | Addition, subtraction |
<< >> | Binary | Shift left, shift right |
< > <= >= | Comparison | Less than, greater than, less than or equal to, greater than or equal to |
== != | Comparison | Is equal to, not equal to |
& | Binary | And |
^ | Binary | Exclusive or (XOR) |
| | Binary | Or |
&& | Logical | And |
|| | Logical | Or |
?: | Comparison | Weird if thing; associativity goes right to left |
= | Assignment | Variable assignment operator, including the +=, *=, and all assignment operators |
, | (None) | The comma separates items in a for statement; precedence from left to right |
当然,如果一段程序利用括号,就先执行括号内的运算。