第 3章 表 达 式第 3章 表 达 式
3.1 表达式基础
3.2 算术表达式
3.3 赋值表达式
3.4 逻辑表达式
3.5 位运算表达式
3.6 其它表达式第 3章 表 达 式
3.1 表达式基础
3.1.1 表达式的组成
1,运算符运算符又称操作符,是一个符号,它指示在一个或多个操作数上完成某种运算操作或动作 。
C语言中,除了输入,输出及程序流程控制操作以外的所有基本操作都作为运算处理 。
如,赋值运算符,=”,逗号运算符“,”,括号运算符“( )”。
第 3章 表 达 式
① 算术运算符有 +,—,*,/,%,++、
② 关系运算符有 <,<=,==,! =,>,>=
③ 逻辑运算符有 !,&&,||
④ 位运算符有 <<,>>,~,|,^,&
⑤ 赋值运算符有 =,+=,- =,*=,/=,%=
⑥ 条件运算符有?,
⑦ 逗号运算符有,
⑧ 指针运算符有 *,&
⑨ 求字节数运算符有 sizeof
10 强制类型转换运算符有 ( 类型 )
11 其它运算符有,,→,( ),[ ]等第 3章 表 达 式
2,操作数操作数是运算符的操作对象,可以是常量,变量,
函数与表达式 。
常量,变量,函数本身就是简单表达式,从一般意义上讲,C语言中所有操作数都是表达式 。 复杂表达式由运算符连接简单表达式形成 。
第 3章 表 达 式
3.1.2 表达式的书写
C语言的表达式虽然来源于数学表达式,是数学表达式在计算机中的表示,但在书写时应该注意遵循 C语言表达式书写的原则,
(1) C语言的表达式只能采用线性的形式书写 。 例如,
① 应写成 1/3+i+j*j*j。
② 应写成( a+b) /( c+d) *e+f。
3
3
1 ji
fedc ba
第 3章 表 达 式
(2) C语言的表达式只能使用 C语言中合法的运算符和操作数,对有些操作必须调用库函数完成,而且运算符不能省略 。 例如,
① πr2应写成 3.14159*r*r。
② 应写成 0.5*a*b*sin( alph) 。
③ |x- y|应写成 fabs( x- y) 。
④ y+2X 应写成 y+pow( 2,x)。
aab sin21
第 3章 表 达 式
3.1.3
C语言表达式种类很多,有多种分类方法 。 我们一般依据运算的特征将表达式分为,
① 算术表达式,如 a+b*2.0-3.0/5.0。
② 关系表达式,如 x>=y,关系表达式可以认为是逻辑表达式的特殊情况 。
③ 逻辑表达式,如 ( x>=2) &&( x<=8) 。
④ 赋值表达式,如 a=b=c=1。
⑤ 条件表达式,如 ( a>b)?a,b。
⑥ 逗号表达式,如 a=2,b=a*a,c=sqrt( b)。
第 3章 表 达 式
3.1.4 表达式的计算1,
C语言将运算符的优先级划分为 15级,初等运算 ( )、
[ ],→,,优先级最高,单目运算 !,~,++,--,
-,( 类型 ),*,&,sizeof优先级次高,算术运算 +、
-,*,/,% 再次之,然后是关系运算 <,<=、
==,![KG-*4]=,>,>=,再然后是逻辑运算 &&,||,条件运算式?,,赋值运算 =,+=,-=,*=,/=,%=,逗号运算优先级最低,位运算优先级比较分散 。
第 3章 表 达 式
2,运算符的结合性运算符的结合性是指,优先级相同的运算从左到右进行 ( 左结合性 ) 还是从右至左进行 ( 右结合性 ),左结合性是人们习惯的计算顺序 。
C语言中,只有单目运算 ( !,~,++,--,-、
*,&),条件运算 (?,),赋值运算 ( =,+=,-=、
*=,/=,%=) 的结合性是右结合,其余运算为左结合 。
第 3章 表 达 式
3.
一般讲相应的运算只有相应类型的数据才能进行,
不同类型数据进行运算时,要进行类型转换 。 类型转换有自动转换 ( 又称隐含转换 ) 与强制转换两种方式 。
(1) 自动转换 。
自动转换由系统自动完成,转换的规则如图 3-1所示 。
Int usigned long double
↑ ↑
short,char float
图 3 - 1
第 3章 表 达 式纵向箭头方向表示必定要进行的转换,short型,
char型数据必定先转换成 int型,float型数据必定先转换成 double型,再进行运算 。
横向箭头方向表示类型自动转换的方向 。 由低向高转换,int型最低,double型最高 。 int型与 usingned型数据进行运算,int型转换成 unsigned; int型与 long型数据进行运算,int型转换成 long型 ; int型与 double型数据进行运算,int型转换成 double型 。 其它类推 。
这种转换是一种保值映射,在转换中数据的精度不受损失。
第 3章 表 达 式
(2) 强制转换 。
强制类型转换通过类型转换运算进行 。
格式,( 类型名 ) ( 表达式 )
将表达式的类型强制转换成类型名指定的类型 。
如,float x,y;
( int) ( x+y) 将表达式 x+y的值强制转换成整型强制类型转换在将高类型转换为低类型时,数据精度受损,是一种不安全的转换 。 强制类型转换是暂时性的,
一次性的,并不永久改变所转换表达式的类型 。
如,int a;
( double) a为双精度,a依然为整型量。
第 3章 表 达 式例 3 –1 表达式计算 。
(1) float x=2.5,y=4.7; int a=7;
计算 x + a%3*( int) ( x+y)%2/4
⑦ ① ④ ③ ② ⑤ ⑥
① a%3等于 1。
② x+y等于 7.2。
③ ( int) ( x+y) 等于 7。
④ a%3*( int) ( x+y) 等于 7。
⑤ a%3*( int) ( x+y) %2等于 1。
⑥ a%3*( int) ( x+y) %2/4等于 0。
⑦ x+a%3* ( int ) ( x+y ) %2/4 等于 2.5+0,结果为 2.5 。
第二项将由整型自动转换为双精度型进行运算,计算结果为双精度型 。
第 3章 表 达 式
(2) int a=2,b=3; float x=3.5,y=2.5;
计算 ( float) ( a+b) /2 +( int) x%( int) y
② ① ③ ⑦ ④ ⑥ ⑤
① a+b等于 5。
② ( float) ( a+b) 等于 5.0,强制转换成 float型 。
③ ( float) ( a+b) /2等于 5.0/2.0,结果为 2.5。
④ ( int) x等于 3,强制转换成 int型 。
⑤ ( int) y等于 2,强制转换成 int型 。
⑥ ( int) x%( int) y等于 1。
⑦ ( float)( a+b) /2+( int) x%( int) y等于 2.5+1.0,结果为 3.5(双精度型)。
第 3章 表 达 式
(3) int i=3; float f=1.0; double d=2.3;
计算 10 +′a′+i*f-d
① ③ ② ④
① ′a′转换成 97,10+′a′等于 107。
② i,f转换成双精度型,i*f等于 3.0。
③ 107转换成双精度型,10+′a′+i*f等于 110.0。 ④
10+′a′+i*f-d等于 107.7。
第 3章 表 达 式
3.2 算术表达式
1,自增运算自增运算符,++
自增运算是单目运算,操作数只能是整型变量,有前置,后置两种方式,
++i,在使用 i 之前,先使 i的值增加 1,俗称先增后用 。
i++,先使用 i的值,然后使 i的值增加 1,俗称先用后增 。
如,i=1999;
j=++ i; /*先将 i 的值增 1,变为 2000,后使用 。 j的值也为 2000*/
j=i++; /*先使用,j的值为 1999。 后增,将 i 的值增 1,变为 2000*/
自增运算优先级处于第 2级,结合自右向左。
第 3章 表 达 式2,自减运算自减运算符,--
自减运算与自增运算一样也是单目运算,操作数也只能是整型变量 。 同样有前置,后置两种方式,
--i,在使用 i之前,先使 i 的值减 1,俗称先减后用 。
i--,先使用 i 的值,然后使 i 的值减 1,俗称先用后减 。
如,i=2000;
j=--i; /*先减,将 i 的值减 1,变为 1999。 后使用,j的值也为 1999*/
j=i--; /*先使用,j的值为 2000。 后减,将 i 的值减 1,i的值变为 1999*/自减运算的优先级,结合性同自增运算 。
第 3章 表 达 式请特别注意,
(1) 自增,自减运算只能用于整型变量,不能用于常量或表达式 。
(2) 自增,自减运算比等价的赋值语句生成的目标代码更高效 。
(3) 该运算常用于循环语句中,使循环控制变量自动加,减 1,或用于指针变量,使指针指向下一个或上一个地址 。
(4) 表达式中包含有自增,自减运算时,容易出错,务请小心 。
如,i=1;
( ++i) +( ++i) +( ++i) 的值为多少呢? 有的计算出 9( =2+3+4)
其实这是错误的 。 计算时先对整个表达式扫描,i 先自增 3
次,由 1→ 2→ 3→ 4,如此计算结果为 4+4+4,等于 12。,
( i++) +( i++) +( i++) 的值又是多少呢? 类似上面分析,应为 3,当然表达式计算完成后 i 的值同样改变为 4。
第 3章 表 达 式
3.
C语言的运算符一般为一个字符,有的由两个字符组成,在表达式中出现多个字符时如何组合呢? C编译系统在处理时原则上尽可能自左而右将若干字符组合成一个运算符,标识符,关键字也按同样的原则进行处理 。
如 i+++j,解释为( i++) +j,非 i+( ++j)。 如要表示
i+( ++j),必须加括号。
第 3章 表 达 式例 3– 2 自增自减运算 。
/*程序 3 - 2,自增自减运算 */
# include″stdio.h″
main( )
{int i,j;
i=j=5;
printf( ″i++=%d,j-- =%d\n″,i++,j-- ) ;
printf( ″++i=%d,-- j=%d\n″,++i,-- j) ;
printf( ″i++=%d,j-- =%d\n″,i++,j-- ) ;
printf( ″++i=%d,-- j=%d\n″,++i,-- j) ;
printf( ″i=%d,j=%d\n″,i,j) ;
}
第 3章 表 达 式运行结果,
i++=5,j-- =5
++i=7,-- j=3
i++=7,j-- =3
++i=9,-- j=1
i=9,j=1
第 3章 表 达 式
3.3 赋值表达式
3.3.1 赋值运算赋值运算符,=
赋值运算是双目运算,一个操作数为变量,一个操作数为表达式 。 赋值运算符的右边是表达式,左边是变量 。
赋值运算时先计算右边表达式的值,然后将右边表达式的值赋给左边变量,即送给左边变量对应的存储单元,
并以此作为整个赋值表达式的值 。
第 3章 表 达 式如,int i;
i=3+5%2; /*先计算 3+5%2,得到 4,然后将 4 赋给 i*/ 。
赋值运算的优先级为第 14级,次低,结合自右向左 。
赋值运算中的表达式操作数最简单的形式是一个常量,这时让变量得到一个初值 。
如,int i; float x; char ch;
i=100; x=12.345; ch=′A′;
赋值运算中表达式操作数又可以是赋值表达式,如此可辗转赋值 。
如,int x,y,z;
x=y=z=0.0; /*相当于 x=( y=( z=0.0)),x,y,z都得到值 0.0*/
③ ② ①
第 3章 表 达 式
3.3.2 赋值类型转换
( 1) 将实型数据赋给整型变量时,舍弃实数的小数部分 。
如,int i;
i=1.23; /*结果 i 的值为 1*/
(2) 将整型数据赋给单,双精度型变量时,数值大小不变,但以浮点形式存储到变量中 。
第 3章 表 达 式
(3) 将字符型数据赋给整型变量时,由于字符数据只占一个字节,而整型变量为两个字节,将字符的数据放整型变量的低 8位,而对整型变量的高 8位进行扩充 。
(4) 将基本整型数据赋给长整型变量时,基本整型数据放长整型变量低 16位,高 16位用符号位扩充 。 反之将长整型数据赋给整型变量时,只需将长整型数据的低 16
位原封不动送整型变量中 。 例如,
第 3章 表 达 式
① int i=- 1;
long int j;
j=i;
i 的二进制形式,1000000000000001
j 的二进制形式,11111111111111111000000000000001
② long int i =- 1;
int j;
j=i;
i 的二进制形式,10000000000000000000000000000001
j 的二进制形式,0000000000000001
第 3章 表 达 式
(5) 将无符号整型数据赋给长整型变量时,不存在符号扩展的问题,只需将高位补 0即可 。 将无符号整型数据赋给一个占字节数相同的整型变量时,将无符号整型数据原样送整型变量中,并将最高位当作符号位,如果数据超出相应的整型范围,将产生数据错误 。 如果将整型数据赋给占字节数相同的无符号整型变量,也是原样照赋,最高位作数值处理 。
例如,
① unsigned int i=65535;
int j;
j=i; /* j的值为 -1*/
② int i =- 1;
unsigned int j;
j=i; /*i 的值为 65535*/
第 3章 表 达 式
3.3.3 复合赋值运算在基本赋值运算符,=”之前加上任一双目算术运算符及位运算符可构成复合赋值运算符,又称带运算的赋值运算符 。
算术复合赋值运算符,+=,- =,*=,/=,%=
位复合赋值运算符,&=,|=,^=,> >=,< <=
一般形式,变量 ☆ =
等价于,变量 =变量 ☆
☆ 代表任一双目算术运算符或位运算符 。
复合赋值运算先进行所带运算,再进行赋值运算。 复合赋值运算的优先级同赋值运算。
第 3章 表 达 式
(1) int a=3;
a+=2 等价于 a=a+2
(2) float x=1.2,y=2.1;
y*=x+3.4 等价于 y=y*( x+3.4)
(3) int a=1,b=2;
b/=a+=1,等价于 b=b/( a=a+1)
第 3章 表 达 式例 3 –3 赋值运算 。
/*程序 3 - 3,赋值运算 */
# include ″stdio.h″
main( )
{int i,j;
float x,y;
i=j=1;
x=y=1.1;
printf( ″i=%d,j=%d\n″,i,j) ;
x=i+j;
y+=1;
第 3章 表 达 式
printf( ″x=%4.2f,y=%4.2f\n″,x,y) ;
i=i+++j;
x=2*x+y;
printf( ″i=%d,x=%4.2f \n″,i,x) ;
}
运行结果,
i=1,j=1
x=2.00,y=2.10
i=2,x=6.10
第 3章 表 达 式
3.4 逻辑表达式
3.4.1 关系表达式关系表达式是逻辑表达式中的一种特殊情况,关系表达式由关系运算符和操作数组成,关系运算用于完成数的比较运算 。 关系运算有 <,<=,==,!=,>,>=,<、
<=,>,>=的优先级相同,==,!=的优先级相同,前者的优先级高于后者 。 关系运算符的优先级低于算术运算,高于逻辑运算 &&,||,也高于赋值运算 。
第 3章 表 达 式逻辑表达式由逻辑运算符和关系表达式或逻辑量组成,逻辑表达式用于程序设计中的条件描述 。
C语言有 !,&&,||等三种逻辑运算 。 ! 运算的优先级高于算术运算,&&运算高于 ||运算,&&,||运算低于关系运算,高于赋值运算 。
3.4.2 逻辑表达式第 3章 表 达 式
&&和 ||是一种短路运算 。 所谓短路运算,是指在计算的过程中,只要表达式的值能确定,便不再计算下去 。
如逻辑与运算时计算到某个操作数为假,可确定表达式的值为假,剩余的操作数不再考虑 ; 逻辑或运算时计算到某个操作数为真,可确定表达式的值为真,剩余的操作数也不再需要考虑 。 例如,
(1) e1&&e2,若 e1 为 0,可确定表达式的值为 0,不再计算 e2。
(2) e1||e2,若 e1为真,则可确定表达式的值为真,也不再计算 e2。
第 3章 表 达 式例 3 — 4 用逻辑表达式描述下列条件,
(1) x是 3 的倍数 。
x%3==0
(2) x是偶数 。
x%2==0
(3) x是 3 的倍数且 x是偶数 。
( x%3==0) &&( x%2==0)
第 3章 表 达 式
(4) 100<x<200。
( x>100) &&( x<200)
(5) x等于 2或 8。
( x==2) ||( x==8)
(6) 某年是否为闰年 。
( year %400==0) ||(( year%4==0) &&
( year%100!=0))
第 3章 表 达 式
3.5 位运算表达式
3.5.1 位逻辑运算
1,按位取反运算运算符,~
按位取反运算用来对一个二进制数按位取反,即 0 位变 1,1 位变 0。
第 3章 表 达 式例如,~ 25,25的二进制表示为,
0000000000011001
按位取反得结果,
1111111111100110,即 -26。
~运算常用于产生一些特殊的数 。 如高 8 位全 1 低
8 位全 0 的数 0xFF00,按位取反后变为 0x00FF。 ~ 1,在
16 位与 32 位的系统中,都代表只有最低位为 0 的整数 。
~运算是位运算中唯一的单目运算,也是唯一具有右结合性的位运算 。
第 3章 表 达 式
2,按位与运算运算符,&
按位与运算的规则是操作数的对应位都为 1,则该位的运算结果为 1,否则为 0。 例如,0x29&0x37,0x29 与
0x37 的 二 进 制 表 示 为,0000000000101001 与
0000000000110111
按位与结果为,00000000000100001,即 0x21。
按位与运算主要用途是清零及取数的某些位或保留数的某些位 。 例如,
(1) a&0,将 a清 0。
(2) a&0xFF00,取数 a的高 8 位,低 8 位清 0。
(3) a&0x00FF,取数 a的低 8 位,高 8 位清 0。
第 3章 表 达 式
3,按位或运算运算符,|
按位或运算的规则是操作数的对应位都为 0,则该位的运算结果为 0,否则为 1。
例如,0x29 | 0x37,0x29 与 0x37 的二进制表示为,
0000000000101001与 0000000000110111
按位或结果为,
0000000000111111,即等于 0x3f。
利用 | 运算可将数的部分位或所有位置 1。
第 3章 表 达 式例如,
(1) a | 0x000F,a的低 4 位全置 1,其它位保留。
(2) a | 0xFFFF,a的每一位全置 1。
第 3章 表 达 式
4.
运算符,^
按位异或运算的规则是操作数的对应位相同,则该位的运算结果为 0,否则为 1。
例如,0x29^0x37,0x29 与 0x37 的二进制表示为,
0000000000101001与 0000000000110111
按位异或结果为,
0000000000011110,即等于 0x1e。
利用 ^运算将数的特定位翻转,保留原值,不用临时变量交换两个变量的值。
第 3章 表 达 式例如,
(1) a^0x00FF,将数 a的低 8 位翻转,高 8 位不变 。
(2) a^0,保留数 a的原值 。
(3) a=a^b,b=b^a,a=a^b,不用临时变量交换 a#,b的值 。
位逻辑运算自身的优先级由高到低依次是~,&,|、
^,在整个运算体系中~运算的优先级位于第二级,&,|、
^ 运算低于关系运算,高于逻辑运算 。
位逻辑运算意义与逻辑运算一样,但位逻辑运算对二进制位而言,且必须对数的所有二进制位进行,而且操作数只能为整数 。
如果参与运算的数据长度不同,将对短的数据先进行高位符号扩展后再进行位运算。
第 3章 表 达 式
3.5.2 移位运算
1.
运算符,<<
移位运算的左操作数是要进行移位的整数,右操作数是要移的位数 。
左移位运算规则是高位左移后溢出,舍弃,空出的右边低位补 0。
例如,15<<2,15 的二进制表示为,0000000000001111
左移 2位结果为,0000000000111100,等于 60。
左移 1 位相当于该数乘以 2,左移 2 位相当于该数乘以
4( 22) 。 使用左移位运算可以实现快速乘 2 运算 。
第 3章 表 达 式
2,右移位运算运算符,>>
右移位运算规则是低位右移后被舍弃,空出的左边高位对无符号数移入 0。 如果是有符号数,对正数空出的左边高位移入 0; 如果是负数,则左边移入 0 还是 1,
要取决于所用编译系统,有的移入 0( 逻辑右移 ),有的移入 1( 算术右移 ) 。
第 3章 表 达 式例如,15>>2,右移 2 位,等于 0000000000000011,
即 3。
右移 1 位相当于该数除以 2,右移 2 位相当于该数除以 4( 2 2) 。 使用右移位运算可以快速实现除 2
运算 。
移位运算低于算术运算,高于关系运算 。
位运算与赋值运算可组合成复合赋值运算 &=、
|=,^ =,< <=,> >= 。
第 3章 表 达 式例 3 — 5 取一个整数 a的从右端开始的 4~ 7 位 。
/*程序 3 — 5,取一个整数 a的从右端开始的 4~ 7 位 */
# include″stdio.h″
main( )
{unsigned a,b,c,d;
scanf( ″%o″,&a) ; /*八进制形式输入 */
b=a>>4; /*a右移 4位 */
c=~ ( ~ 0<<4) ; /*得到一低 4位全为 1,其余位为 0的数 */
d=b&c; /*取 b的 0~ 3位,即得到 a的 4~ 7位 */
printf( ″a=%o,a( 4~ 7) =%o″,a,d) ;
}
输入数据,331
运行结果,a=331,a( 4~ 7) =15
第 3章 表 达 式
3.6 其它表达式
3.6.1 条件表达式条件表达式由条件运算符和操作数组成,用以将条件语句以表达式的形式出现,完成选择判断处理 。
条件运算符由,?,和,,,组成 。
条件运算是三目运算,有三个操作数,一般形式如下,
表达式 1? 表达式 2,表达式 3
第 3章 表 达 式表达式 1 必须为逻辑表达式,如表达式 1为真,计算表达式 2,并以此作为整个表达式的值 。 如表达式 1 为假,计算表达式 3,并以此作为整个表达式的值 。
(1) a>b? a,b
a大于 b,表达式的值为 a; a小于 b,表达式的值为 b。 实际上求 a,b的最大值 。
(2) a>0? a,- a
a大于 0,表达式的值为 a; a小于等于 0,表达式的值为
- a。 实际上求 a 的绝对值 。
条件运算的优先级为倒数第 3 级,高于赋值运算,低于逻辑运算,结合从右至左 。
如 a>b? a,c>d? c,d,相当于 a>b? a,( c>d? c,d)
第 3章 表 达 式例 3 — 6 判断整数的正负 。
/*程序 3 — 6,判断整数的正负 */
# include ″stdio.h″
main( )
{ int x;
scanf( ″%d″,″&x″) ;
x>0? printf( ″%s″,″正数 ″),printf( ″%c″,″负数 ″) ;
}
第 3章 表 达 式
3.6.2 逗号表达式逗号表达式由逗号运算符和操作数组成,用以将多个表达式连接成一个表达式 。
逗号运算符,,
逗号运算是双目运算,一般形式如下,
表达式 1,表达式 2
先计算表达式 1,再计算表达式 2,并以此作为整个表达式的值 。
如 a=2,a*6,先计算 a=2,再计算 a*6,并以此作为整个表达式的值,表达式的值为 12。
逗号运算的优先级最低,结合自左向右。
第 3章 表 达 式逗号表达式的更一般使用形式为,
表达式 1,表达式 2,表达式 3,……,表达式 n
先计算表达式 1,再计算表达式 2,再计算表达式
3,…,再计算表达式 n的值,并以此作为整个表达式的值 。
如表达式 x=a=3,6*x,6*a,a+x的值为 6。
逗号运算又称顺序求值运算。
第 3章 表 达 式
3.6.3 其它运算
1,取地址运算运算符,&
取地址运算是单目运算,操作数只能是变量,得到变量的地址 。 C语言程序设计中许多场合要使用到地址数据 。
如输入函数 scanf( ),输入参数就要求是地址表,将读入的数据送变量对应的存储单元中 。
取地址运算的优先级次高 。
C语言还提供一个指针运算,*”,用于取存储单元的内容,
第 3章 表 达 式
2.
运算符,sizeof
求字节数运算是单目运算,操作数可以是类型名,
也可以是变量,表达式,用以求得相应类型或数据所占的字节数 。
此运算的优先级与取地址运算优先级相同。
第 3章 表 达 式
3.
在其它语言中括号是某些语法成分的描述方式,C
语言将括号亦作为运算处理 。
(1) 圆括号运算 ( ):
用于改变运算的优先级,还用于将函数的参数与函数名相分离 。
(2) 中括号运算 [ ],
又称下标运算,用来得到数组的分量下标变量 。
括号运算的优先级处于最高一级。