《C语言程序设计与实践(第2版)》——3.4 表达式和运算符

本节书摘来自华章出版社《C语言程序设计与实践(第2版)》一书中的第3章,第3.4节,作者:凌云等著,更多章节内容可以访问云栖社区“华章计算机”公众号查看

3.4 表达式和运算符

C语言的运算符范围很广,具有非常丰富的运算符和表达式运算,为编写程序提供了方便。表达式是由操作数和运算符组成,运算后产生一个确定的值,其中操作数可以是常量、变量、函数和表达式,每个操作数都具有一种数据类型,通过运算得到的结果也具有一种数据类型,结果的数据类型与操作数的数据类型可能相同,也可能不相同。运算符指出了表达式中的操作数如何运算。C语言中共有44种运算符,根据各运算符在表达式中的作用,表达式大致可以分成算术表达式、关系表达式、逻辑表达式、条件表达式、赋值表达式和逗号表达式等。
在一个表达式中,若有多个运算符,其运算次序遵照C语言规定的运算优先级和结合性规则,即在一个复杂表达式中,看其运算的顺序,首先要考虑优先级高的运算,当几个运算符优先级相同时,还要按运算符的结合性,自左向右或自右向左计算。下面具体介绍这些运算符。在运算符的学习中,我们要从运算符功能、要求操作数个数、要求操作数类型、运算符优先级别、结合方向以及结果的类型等方面去考虑。
3.4.1 算术运算符
表3-4列出了C语言中允许的算术运算符。在C语言中,运算符“+”“-”“*”和“/”的用法与大多数计算机语言的相同,几乎可用于所有C语言内定义的数据类型。当“/”被用于整数或字符时,结果取整。例如,在整数除法中,10 / 3 = 3,而不是3.333333。
screenshot

一元减法的实际效果等于用-1乘以单个操作数,即任何数值前放置减号将改变其符号。模运算符“%”在C语言中的用法与它在其他语言中的用法相同。切记,模运算取整数除法的余数,所以“%”不能用于float和double类型。
下面通过一小段程序来说明%的具体用法。

int x, y;
x = 10;
y = 3;
printf("%d", x / y );    /* 输出3 */
printf("%d", x % y );     /* 输出1,整数除法的余数 */
x = 1;
y = 2;
printf("%d,%d", x / y, x % y);     /* 输出0,1 */

最后1行打印一个0和一个1,因为1 / 2商为0,余数为1,故1 % 2取余数1。
C语言中有两个很有用的运算符“++”和“--”,其中运算符“++”称为自增运算符,表示操作数自身加1,而“--”称为自减运算符,表示操作数自身减1,换句话说,
++x; 同x = x + 1;
--x; 同x = x – 1;
自增和自减运算符可用在操作数之前,也可放在其后,例如,“x = x + 1;”可写成“++ x;”或“x ++;”,但在表达式中,这两种用法是有区别的。自增或自减运算符在操作数之前,C语言在引用操作数参与表达式运算之前就先执行加1或减1操作;运算符在操作数之后,C语言就先引用操作数的值参与表达式计算,而后再进行加1或减1操作。通俗地说,自增或自减运算符在操作数之前表示变量先进行自加或自减运算,然后再用新的变量值参与表达式的计算;自增或自减运算符在操作数之后表示用变量原先的值先参与表达式的计算,然后再进行变量自加或自减运算。请看下例:
x = 10;
y = ++x;
此时,y = 11。如果语句改为:
x = 10;
y = x++;
则y = 10。在这两种情况下,x都被置为10,但区别在于设置的时刻,这种对自增和自减发生时刻的控制是非常有用的。在大多数C编译程序中,为自增和自减操作生成的程序代码比等价的赋值语句生成的代码要快得多,所以尽可能采用加1或减1运算符是一种好的选择。
screenshot

编译程序对同级运算符按从左到右的顺序进行计算。当然,括号可改变计算顺序。C语言处理括号的方法与几乎所有计算机语言相同,即强迫某个运算或某组运算的优先级升高。
++和--的结合方向是“自右向左”。前面已经提到,算术运算符的结合方向为“自左向右”,这是大家熟悉的。如果有:
-i++;
变量i的左边是负号运算符,右边是自增运算符,两个运算符的优先级相同,按照“自右向左”的结合方向,它相当于:
-(i++);
假如i = 3;如果有:
printf("%d", -i++);
则先取出i的值使用,输出-i的值-3,然后使i增值为4。
注意:(i++)是先用i的原值进行运算以后,再对i加1。不要认为先加完1以后再加负号,输出-4,这是错误的。
3.4.2 赋值运算符
赋值运算符分为简单赋值运算符和复合赋值运算两种。
简单的赋值运算的一般形式为:
<变量标识符> = <表达式>
其中,“=”号是赋值运算符。其作用是将一个表达式的值赋给一个变量,同时将该值作为赋值表达式的结果。如a = 5 % 3的作用是首先执行取余运算,然后执行赋值运算(因为%的优先级高于=的优先级),即把表达式5 % 3的结果2赋给变量a,同时把该值2作为这次赋值运算的结果。
说明:
1)在C语言中,可以同时对多个变量赋值。
例如,a = b = c = d = 0;
上述语句表示将a、b、c、d变量赋零值。根据运算符“自右向左”的结合性,该表达式从右向左依次赋值。相当于:
a =(b =(c =(d = 0)));
2)如果赋值运算符两侧的操作数的类型不一致,那么在赋值时要进行类型转换,即将右侧表达式的类型自动转换成左侧变量的类型,再赋值。最后将表达式类型转换以后的值作为赋值运算的结果。
① 若将浮点型数据(包括单、双精度数)赋给整型变量,则舍去实数的小数部分。例如,
int i;
i = 3.56; /* 变量i的值为3 */
② 若将整型数据赋给单、双精度变量,则数值不变,但以浮点数形式存储到变量中。例如,
float f;
f = 23; /* 先将23转换成23.00000,再存储在f中 */
C语言中提供的赋值运算符,除了常用的简单赋值运算符“=”外,还有10种复合的赋值运算符。在简单赋值运算符“=”之前加上其他运算符,就构成了复合赋值运算符。如在“=”前加一个“+”运算符,就构成了复合赋值运算符“+=”。
screenshot
screenshot

以“a += 3;”为例来说明,它相当于使a进行一次自加3的操作,即先使a加3,然后再将结果赋给a。同样,“x *= y + 8;”的作用是使x乘以(y + 8),再将结果赋给x。
说明:
1)复合运算符相当于两个运算符的结合。
例如,a += b相当于a = a + b,但并不等价。在C语言中,可将复合赋值运算符看作一个运算符,a只被计算一次,而后一个式子中,a被计算两次,先运算一次,后赋值一次,所以使用复合赋值运算符,可使程序精练,缩短程序代码,提高执行效率。
2)在复合赋值运算中,若赋值号的右侧是复杂表达式,则将右侧的表达式看作一个整体与x进行有关计算。例如,“x = y + 10 - z;”相当于“x = x (y + 10 *- z);”,而不是
“x = x * y + 10 - z;”。
用赋值运算符将一个变量和一个表达式连接起来的式子称为“赋值表达式”。
它的一般形式为:
<变量标识符> <赋值运算符> <表达式>
如a = 5是一个赋值表达式。对赋值表达式的求解过程是:将赋值运算符右侧的“表达式”的值赋给左侧的变量。赋值表达式的值就是被赋值的变量的值。例如,赋值表达式a = 5的值为5(变量a的值也是5)。
上述一般形式的赋值表达式中的“表达式”,也可以是一个赋值表达式。例如,
A = (b = 5);
括号内的b = 5是一个赋值表达式,它的值等于5,因此“a = (b = 5);”相当于b = 5, a =
5,a 的值等于5,整个表达式的值也等于5。因为赋值运算符的结合方向是“自右向左”,所以b = 5外面的括号可以不要,即“a = (b = 5);”和“a = b = 5;”等价。下面是赋值表达式的示例:
screenshot

赋值表达式也可以包含复合赋值运算符。设a的初值为8,表达式
screenshot

也是一个赋值表达式,根据优先级和结合性,此赋值表达式的求解过程为:
screenshot

3.4.3 关系运算符
关系运算是逻辑运算中比较简单的一种。所谓“关系运算”就是“比较运算”,将两个数值进行比较,判断其比较的结果是否符合给定的条件。例如,a > 2是一个关系表达式,大于号“>”是一个关系运算符,如果a的值为3,则满足给定的“a > 2”这一条件,因此该关系表达式的值为“真”(即“条件满足”);如果a的值为1,不满足“a > 2”这一条件,则该关系表达式的值为“假”。
C语言提供了6种关系运算符,见表3-5。
screenshot

说明:
1)参加比较的数据可以是整型、浮点型、字符型或者其他类型。
2) 前四种关系运算符(<、<=、>、>=)的优先级相同,后两种关系运算符的优先级也相同。前4种运算符的优先级高于后两种。例如,“<”优先于“!=”。而“>”与“<”优先级相同。
3)关系运算符的优先级低于算术运算符。
4)关系运算符的优先级高于赋值运算符。
用关系运算符将两个数值或数值表达式连接起来的式子,称为关系表达式。例如,
a + b > c + d
'a' < 'd'
关系表达式的值是一个逻辑值,即“真”或“假”。C语言没有提供逻辑类型数据,而用不等于0的数代表逻辑真(true),用整型数0代表逻辑假(false)。假如变量a、b定义为:
int a = 3, b = 1;
则表达式a > b的值为1,表示逻辑真(true)。
关系运算符的两侧也可以是关系表达式。如果定义:
int a = 3, b = 1, c = -2, d;
则表达式
a > b != c
的值为1;(因为1 != -2是正确的,所以a > b的值为1,即逻辑真);
a == b < c
的值为0,表示逻辑假(false)。
b + c < a
的值为1,表示逻辑真(true)。
如果有以下表达式:
d = a > b
则d的值为1;
d = a > b < c
则d的值为0,因为关系运算符“>”和“<”优先级相同,按“自左至右”的方向结合,先执行“a > b”得到的值为1,再执行关系运算“1 < c”,得到的值为0,赋给d,最终d的值为0。
假设变量x在[0, 10]范围内,对应的数学表达式为0≤x≤10,若将此式误写成C语言表达式:
0 <= x <= 10
这时C语言的编译系统不会指出错误(而在其他程序设计语言中会编译出错)。其计算结果不管x取何值,表达式的值总为1,请读者思考这是为什么。
3.4.4 逻辑运算符
C语言提供了三种逻辑运算符:
&$      逻辑与
||         逻辑或
!          逻辑非
“&&”和“||”是双目(元)运算符,它要求有两个操作数(或运算对象)参与运算,运算结果是整型数1或0,分别表示逻辑真(true)或逻辑假(false)。例如,

(a > b) && (x > y)
(a > b) || (x > y)

“!”是单目(元)运算符,只要求有一个操作数,如“! (a>b)”。
表3-6给出了三种逻辑运算符的优先级。
screenshot

逻辑运算举例如下:

a && b;    // 若a和b都为真,则结果为真;否则,为假
a || b;    // 若a和b中有一个为真,则结果为真;二者都为假时,结果为假
!a;    // 若a为真,则!a为假;若a为假,则!a为真

表3-7为逻辑运算的真值表。用它表示当a和b的值为不同组合时,各种逻辑运算所得到的值。
screenshot

说明:
1)参加逻辑运算的数据类型可以是整型、浮点型、字符型、枚举型等。
2)优先级。
 ①当一个逻辑表达式中包含多个逻辑运算符时,优先级如下;
   !(非)→ &&(与)→ ||(或),即“!”是三者中最高的。
 ②逻辑运算符中的“&&”和“||”低于关系运算符,“!”高于算术运算符。例如,
    (a > b) && (x > y)    可写作 a > b && x > y
 (a == b) || (x == y)    可写作 a ==b || x == y
 (!a) || (a > b)               可写作!a || a > b

若一个表达式中出现算术、关系、逻辑等多种运算时,要分清优先级。为程序清晰起见,可以通过圆括号以显式规定运算次序。
上面的描述中已经多次提到了“真”和“假”这一概念,很多读者可能对此感觉非常困惑。下面对这一概念进行梳理。总的来说,C语言中的“真”和“假”可以分为广义和狭义两种。狭义的“真”和“假”的概念中,用1表示真,用0表示假。C语言在表示逻辑或关系运算结果时,采用的是狭义的“真”和“假”的概念,也就是以数值1代表“真”,以“0”代表“假”。广义的“真”和“假”中,用非0表示真,只有0才表示假。C语言在判断一个用值或表达式表示的条件是否为“真”时,采用的是广义的概念,以0代表“假”,以非0代表“真”,即将一个非0的数值认作为“真”。事实上,狭义的“真”和“假”的概念基本上只会在表示运算结果时才会用到,其他绝大部分情况用的都是广义的“真”和“假”的概念。例如,
1)若a = 3,则!a的值为0。因为a的值为非0,被认作“真”,对它进行“非运算”,结果为“假”。“假”以0代表。
2)若a = 3,b = 4,则a && b的值为1。因为a和b均为非0,被认为是“真”,因此a && b的值也为“真”,值为1。
3)若a = 3,b = 4,a || b的值为1。
4)若a = 3,b = 4,!a && b的值为0。
5)若a = 3,b = 4,!a || b的值为1。
6)4 && 0 || 2的值为1。
通过这几个例子可以看出,由系统给出的逻辑运算结果不是0就是1,不可能是其他数值。而在逻辑表达式中作为参加逻辑运算的运算对象(操作数)可以是0(“假”)或任何非0的数值(按“真”对待)。如果在一个表达式中不同位置上出现数值,应区分哪些是作为数值运算或关系运算的对象,哪些是作为逻辑运算的对象。例如,
6 > 5 && 0 || 3 < 4 - !2
表达式自左至右扫描求解。首先处理“6 > 5”(因为关系运算符“>”优先于逻辑运算符“&&”)。在关系运算符“>”两侧的6和5作为数值参加关系运算,“6 > 5”的值为1(代表真),再进行“1 && 0 || 3 < 4 - !2”的运算,此时0两侧的运算符“&&”和“||”的优先级相同,由于它们的结合方向为“自左至右”,因此先进行“1 && 0”的运算,得到结果0。再往下进行“0 || 3 < 4 - !2”的运算,3的左侧为“||”运算符,右侧为“<”运算符,根据优先规则,应先进行“<”的运算,即先进行“3 < 4 - !2”的运算。现在4的左侧为“<”运算符,右侧为“-”运算符,而“-”优先于“<”,因此应先进行“4 - !2”的运算,由于“!”的优先级别最高,因此先进行“!2”的运算,得到结果0。然后进行“4 - 0”的运算,得到结果4,再进行“3 < 4”的运算,得1,最后进行“0 || 1”的运算,结果为1。
实际上,逻辑运算符两侧的运算对象可以是0和1,或者是0和非0的整数,也可以是字符型、浮点型或其他类型。系统最终以0和非0来判定它们属于“真”或“假”。例如,
'A' && 'D'
的值为1(因为'A'和'D'的ASCII值都不为0,按“真”处理)。
在逻辑表达式求解时,并非所有逻辑运算符都被执行,只是在必须执行下一个逻辑运算符才能求出表达式的解时,才执行该运算符。这种特性被称为短路特性。例如,

int a = 1, b = 2, c = 4, d = 5;
a > b && (c = c + d)

先计算“a > b”,其值为0,此时已能判定整个表达式的结果为0,所以不必再进行右边“(c = c + d)”的运算,因此c的值不是9而仍然保持原值4。
同样,在进行多个||运算时,当遇到操作数为非0时,也不必再进行其右面的运算,表达式结果为1。例如,
a - 4 || b < 5 || c > a
先计算“a - 4”,其值为非0(代表真),后面两个关系表达式就不需要再判断,因为已经能确定该逻辑表达式的值为1。反之,继续判断b < 5是否为非0,以此类推。
熟练掌握C语言的关系运算符和逻辑运算符后,可以巧妙地用一个逻辑表达式来表示一个复杂的条件。
例如,判别用year表示的某一年是否为闰年。闰年的条件是符合下面二者之一:
① 能被4整除,但不能被100整除,如2016。
② 能被400整除,如2000。
可以用一个逻辑表达式来表示:
(year % 4 == 0 && year % 100 != 0) || year % 400 == 0
当year为整型时,如果上述表达式的值为1,则year为闰年;否则,为非闰年。
可以加一个“!”用来判别非闰年:
!((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
若此表达式值为1,则year为非闰年。
也可以用下面逻辑表达式判别非闰年:
(year % 4 != 0) ||(year % 100 == 0 && year % 400 != 0)
若表达式值为真,则year为非闰年。请注意表达式中不同运算符的运算优先次序。
3.4.5 位运算符
位运算是指按二进制进行的运算。在系统软件中,常常需要处理二进制位的问题。C语言提供了6个位运算符。这些运算符只能作用于整型操作数,即只能作用于带符号或无符号的char、short、int与long类型。表3-8所示即为C语言提供的位运算符。
screenshot

1.“按位与”运算符(&)
“按位与”是指参加运算的两个数据,按二进制位进行“与”运算。如果两个相应的二进制位都为1,则该位的结果值为1;否则,为0。这里的1可以理解为逻辑中的true,0可以理解为逻辑中的false。“按位与”其实与逻辑上“与”的运算规则一致。逻辑上的“与”,要求运算数全真,结果才为真。
若A = true,B = true,则A & B = true。
例如,求11 & 9的值。
11的二进制编码是1011,内存存储数据的基本单位是字节(Byte),一个字节由8个位(bit)组成。位是用以描述计算机数据量的最小单位。二进制系统中,每个0或1就是一个位。将1011补足成一个字节,则是00001011。
9的二进制编码是1001,将其补足成一个字节,则是00001001。
对两者进行“按位与”运算:
      00001011
&   00001001
      00001001
由此可知11 & 9 = 9。
“按位与”的用途主要有:
(1)清零 若想对一个存储单元清零,即使其全部二进制位为0,只要找一个二进制数,使其中各个位符合以下条件:原来的数中为1的位,新数中的相应位为0。然后使两者进行&运算,即可达到清零的目的。例如整数93,二进制编码为01011101,另找一个整数162,二进制编码为10100010,将两者“按位与”运算:
    01011101
& 10100010
    00000000
事实上,一种更加简单的方法就是直接与0做“按位与”运算,任何数都将被清零。
(2)取一个数中某些指定位 若有一个整数a(假设占两个字节),想要取其中的低字
节,只需要将a与8个1“按位与”即可。
    a 00101100 10101100
& b 00000000 11111111
    c 00000000 10101100
(3)保留指定位与一个数进行“按位与”运算,此数在该位取1。例如,有一数84,即01010100,想把其中从左边算起的第3、4、5、7、8位保留下来,则运算如下:
    01010100
& 00111011
    00010000
即a = 84,b = 59, c = a & b = 16。
2. “按位或”运算符(|)
“按位或”运算符的规则是:两个数相应的二进制位中只要有一个为1,则该位的结果值为1。例如,48 | 15,将48与15进行“按位或”运算。
    00110000
|   00001111
    00111111
“按位或”运算常用来将一个数据的某些位定值为1。例如,如果想使一个数a的低4位为1,则只需要将a与15进行“按位或”运算即可。
3. “按位异或”运算符(^)
“按位异或”运算符的规则是:若参加运算的两个二进制位值相同则为0,否则为1,即0^0=0,0^1=1,1^0=1,1^1=0。
例如,  00111001

^    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00101010
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00010011

按位“异或”的用途主要有:
(1)使特定位翻转 设有二进制数01111010,想使其低4位翻转,即1变0、0变1,可以将其与二进制数00001111进行“异或”运算,即
     01111010
^  00001111
     01110101
运算结果的低4位正好是原数低4位的反转。可见,要使哪几位反转,就将与其进行异或运算的该位置为1即可。
(2)与0相“异或”,保留原值 例如,10^0=10
    00001010
^ 00000000
    00001010
因为原数中的1与0进行异或运算得1,0^0得0,故保留原数。
(3)交换两个值,不用临时变量 例如,a=3,即二进制00000011;b=4,即二进制00000100。想将a和b的值互换,可以用以下赋值语句实现:
a = a ^ b;
b = b ^ a;
a = a ^ b;
      a = 00000011
^ b = 00000100,
则 a = 00000111,转换成十进制,a已变成7;
继续进行
      a = 00000111
^ b = 00000100,
则 b = 00000011,转换成十进制,b已变成3;
继续进行
      b = 00000011
^ a = 00000111,
则 a = 00000100,转换成十进制,a已变成4;
执行前两个赋值语句“a = a ^ b;”和“b = b ^ a;”相当于b = b ^ (a ^ b)。
再执行第三个赋值语句“a = a ^ b”,由于a的值等于(a ^ b),b的值等于(b ^a ^ b),因此,该语句相当于a = a ^ b ^ b ^ a ^ b,即a的值等于a ^ a ^ b ^ b ^ b,等于b。
4. “取反”运算符(~)
“取反”是一个单目运算符,用于求整数的二进制反码,即分别将操作数各二进制位上的1变为0,0变为1。
5. “左移”运算符(<<)
“左移”运算符是用来将一个数的各二进制位左移若干位,移动的位数由右操作数指定(右操作数必须是非负值),其右边空出的位用0填补。若高位左移溢出,则舍弃该高位。
例如,将a的二进制数左移2位,右边空出的位补0,左边溢出的位舍弃。若a=15,即00001111,左移2位得00111100。
左移1位相当于该数乘以2,左移2位相当于该数乘以2×2=4,15<<2=60,即乘以4。但此结论只适用于该数左移时被溢出舍弃的高位中不包含1的情况。
例如,假设以一个字节(8位)存一个整数,若a为无符号整型变量,则a = 64时,左移一位时溢出的是0得到10000000,即128;而左移2位时,溢出的高位中包含1,并不会得到256的二进制数。
6. “右移”运算符(>>)
右移运算符是用来将一个数的各二进制位右移若干位,移动的位数由右操作数指定(右操作数必须是非负值),移到右端的低位被舍弃,对于无符号数,高位补0。对于有符号数,某些机器将对左侧空出的部分用符号位填补(即“算术移位”),另一些机器则对左侧空出的部分用0填补(即“逻辑移位”)。注意:对无符号数,右移时,左侧高位移入0;对于有符号的值,如果原来符号位为0(该数为正),则左侧也是移入0。如果符号位原来为1(即负
数),则左侧移入0还是1要取决于所用的计算机系统。有的系统移入0,有的系统移入1。移入0的称为“逻辑移位”,即简单移位;移入1的称为“算术移位”。
例如,a的值是十进制数38893:
screenshot

Visual C++和其他一些C编译采用的是算术右移,即对有符号数右移时,如果符号位原来为1,左侧移入高位的是1。

  1. 复合赋值运算符
    位运算符与赋值运算符可以组成复合赋值运算符。例如&=、|=、>>=、<<=、^=等。

例如, screenshot

3.4.6 逗号运算符
C语言提供了一种特殊的运算符——逗号运算符,即用逗号将若干个表达式连接起来。例如,
1 + 3, 5 + 7
这样的表达式称为逗号表达式。逗号表达式的一般形式为:
<表达式1>,<表达式2>,<表达式3>,…,<表达式n>
逗号表达式的求解过程:先求解表达式1,再求解表达式2,直到求解完表达式n,最后一个逗号表达式的值作为整个逗号表达式的值。因此,逗号运算符又称为“顺序求解运算符”。例如上面的逗号表达式“1 + 3,5 + 7”的值为12。又如,逗号表达式
screenshot

先求解screenshot,得到a的值为15,然后求解screenshot,得到60,整个逗号表达式的值为60,变量a的值为15。
逗号运算符是所有运算符中级别最低的。因此,下面两个表达式的作用不同:
screenshot

表达式①是一个赋值表达式,将一个逗号表达式的值赋给x, x的值为18。
表达式②相当于screenshot,是一个逗号表达式,它包括一个赋值表达式和一个算术表达式,x的值为3。
其实,逗号表达式无非是把若干个表达式“串连”起来,在许多情况下,使用逗号表达式的目的只是想分别计算各个表达式的值,而并非一定要得到和使用整个逗号表达式的值,逗号表达式常用于循环语句(for)中(详见后面的章节)。
3.4.7 条件运算符
C语言提供了一个简便易用的条件运算符,可以用来代替某些if…then…else语句。条件运算符要求有三个操作对象,为三目(元)运算符,它是C语言中唯一的三目运算符。条件表达式的一般形式为:
表达式1?表达式2:表达式3
说明:
1)条件运算符的执行顺序:先求解表达式1,若为非0(真),则求解表达式2,此时表达式2的值就作为整个条件表达式的值。若表达式1的值为0(假),则求解表达式3,表达式3的值就是整个条件表达式的值。例如,
min = (a < b) ? a : b
执行结果就是将条件表达式的值赋给min,也就是a和b两者中较小者赋给min。
2)条件运算符优先于赋值运算符,因此上面赋值表达式的求解过程是先求解条件表达式,再将它的值赋给min。
条件运算符的优先级别比关系运算符和算术运算符都低。因此,“min = (a < b) ? a : b”,其中的括号可以省略,可写成“min = a < b ? a : b”。如果有“a < b ? a : b – 1;”,相当于“a < b ? a : (b - 1)”,而不是相当于“(a < b ? a : b) - 1”。
3)条件运算符的结合方向为“自右至左”。假设有条件表达式“a > b ? a : c > d ? c : d”,即相当于“a > b ? a : (c > d ? c : d)”,如果a = 1、b = 2、c = 3、d = 4,则条件表达式的值等于4。
4)通常用条件表达式取代简单的条件语句,这部分在后面条件语句中介绍。
3.4.8 运算符的优先级和结合性
表3-9列出了C语言中所有运算符的优先级和结合性,其中包括本书后面将要讨论的某些运算符。如果一个运算对象两侧的运算符的优先级别相同,则运算次序由规定的“结合方向”决定。例如,“”与“/”具有相同的优先级别,其结合方向均为自左至右,因此6 7 / 8的运算次序是先乘后除。“-”和“++”为同一优先级,其结合方向均为“自右至左”,因此-i++相当于-(i++)。
screenshot
screenshot
screenshot

C语言规定了各种运算符的结合方向(结合性),其中单目运算符和三目运算符的结合方向都是“自右至左的结合方向”又称“右结合性”,即在运算对象两侧的运算符为同一优先级的情况下,运算对象先与右侧的运算符结合;除单目运算符、三目运算符和赋值运算符外,其他运算符都是左结合性的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值