c语言程序设计第三章运算符与表达式.docx
- 文档编号:7018296
- 上传时间:2023-01-16
- 格式:DOCX
- 页数:16
- 大小:36.78KB
c语言程序设计第三章运算符与表达式.docx
《c语言程序设计第三章运算符与表达式.docx》由会员分享,可在线阅读,更多相关《c语言程序设计第三章运算符与表达式.docx(16页珍藏版)》请在冰豆网上搜索。
c语言程序设计第三章运算符与表达式
第三章运算符和表达式
3.1运算符和表达式概述
使用运算符可以对运算对象(包括常量和变量)进行计算以得到计算结果。
用运算符将运算对象连接成一个符合C语言语法规则的式称为表达式。
另外,C语言中的表达式是可以嵌套的,即简单表达式经过运算符连接后还可以形成更为复杂的表达式。
根据运算符所连接的运算对象(操作数)的个数,可以将C语言中的运算符分为三类:
(1)单目(一元)运算符:
只连接一个操作数的运算符。
(2)双目(二元)运算符:
带有两个操作数的运算符。
(3)三目(三元)运算符:
同时对三个操作数进行计算的运算符。
C语言中的表达式可以分为三类:
(1)单个常量或者单个变量是最简单的表达式。
(2)带有运算符的表达式。
(3)函数调用。
任何一种运算都是将一定的运算符作用于一定的运算对象上,得到预期的运算结果。
所以运算对象、运算符和运算结果是运算的三大要素。
3.2算术运算符和算术表达式
一、基本算术运算符和简单算术表达式
1.基本算术运算符
C语言为用户提供的基本算术运算符包括:
+(加)、-(减)、*(乘),/(除)、%(求余),这些运算符都是双目运算符,也即在生成算术表达式的时,基本算术运算符左右两侧都必须出现运算对象。
2.简单算术表达式
当用基本算术运算符去连接常量或者变量时,就形成简单算术表达式。
简单算术表达式的基本形式:
data1opdata2。
data1和data2表示某个常量或者变量,op代表上述5个基本算术运算符之一。
假设有变量定义:
inta=20,b=-5;则a+b、a-b、a*-2、20/-b、20%6、a%b等都是简单算术表达式。
3.基本算术运算符使用说明
(1)+、-、*,/既可以连接整型数据,也可以连接实型数据。
当参与这4个运算符的运算对象都是整型数据时,得到整型数据运算结果;否则表示浮点运算。
例如,inta=15,b=2;则a*b等于30,而a/b等于7;a*2.0等于30.0,而a/2.0等于7.5。
(2)在使用除法运算符时要注意右操作数(除数)不能为零。
(3)取余运算%只能对整型数据取余。
另外,由于取余实质上是先进行除法运算,然后得到相除后的余数,所以和除法运算符一样,右操作数不能为零。
例如,inta=15,b=0;double
d=3.0;则a%b和a%d都是非法的表达式。
【例3.1】调用函数printf打印表达式的值。
#include
main()
{
inta=15,b=20;
printf("%d+%d=%d\n",a,b,a+b);
printf("15+20=%d\n",15+20);
printf("%d+5=%d\n",a,a+5);
}
说明:
(1)printf不仅能打印单个常量或者单个变量的值,还能将任意的有值表达式的值打印在
控制台屏幕上。
(2)操作数和运算符之间可以有空白符,见本例程序中的“a+5”。
【例3.2】测试更多的算术运算符。
#include
main()
{
inti=7,j=2;
doubled=2.0;
printf("%d%%%d=%d\n",i,j,i%j);
printf("%d%%%d=%d\n",j,i,j%i);
printf("%d/%d=%d\n",i,j,i/j);
printf("%d/%f=%f\n",i,d,i/d);
}
说明:
(1)%是格式说明符的起始字符,需要用%%来打印%,见本例程序第6行和第7行。
(2)从程序第8行和第9行的运行结果中不难看出,当两个整型数据参与除法运算时结果为整数,否则为浮点数。
4.字符的算术运算
第二章中提到过,由于字符在内存中是用ASCII码存储的,而ASCII码就是一个整数,所以字符数据和整型数据是兼容的,即可以把字符赋给整型变量,也可以把整数赋给字符变量,还可以用转换字符c或d输出字符数据和整型数据。
兼容性还体现在能让字符数据参与算术运算。
【例3.3】对字符进行算术运算。
#include
main()
{
charch1='A',ch2='a';
inti=0x20;
printf("%d,%d\n",ch1+0x20,ch2-i);
printf("%c,%c\n",ch1+0x20,ch2-i);
}
说明:
字符数据参与算术运算时,实际是用该字符的ASCII码值进行相应的计算。
二、自增(++)和自减运算(--)
++和--是两个单目的算术运算符,作用是使变量当前的值加1或减1。
当++或--放在变量名前面时,称为前自增或前自减运算;当++或—放在变量名后面时,称为后自增或后自减运算。
以++为例,前自增运算是先对变量值加1运算,再使用变量的值(自增以后的值);后自增运算是先使用变量原来的值,再对变量值加1。
【例3.4】比较前/后自增运算符的不同。
#include
main()
{
inta=2009,b=a;
printf("a=%d,b=%d\n",a,b);
printf("a++=%d\n",a++);
printf("a=%d\n",a);
printf("++b=%d\n",++b);
printf("b=%d\n",b);
}
说明:
(1)++和—主要用来改变变量的值,所以它们的操作数不能是数值。
例如,4++;就是一条
非法语句。
(2)使用时只连接一个操作数的运算符为单目运算符(或叫一元运算符),所以sizeof和&都是单目运算符。
sizeof可以计算某一类型数据存储时占据的内存字节数,例如sizeof(变量名);&用于获得变量的地址,例如,&变量名。
【例3.5】分析以下程序的运行结果。
交换第5行与第6行后,程序的运行结果?
#include
main()
{
inta=2010;
printf("%d\n",--a);
printf("%d\n",a--);
printf("%d\n",a);
}
说明:
通常,只在单一地对变量加1或减1的情况下才使用自增或自减运算符。
如果让自增/自减运算参与其他操作,有可能会出现意想不到的副作用。
【例3.6】自增/自减运算符的副作用。
#include
main()
{
inti=2010;
printf("i=%d,i++=%d\n",i,i++);
}
说明:
本例在VC6.0下运行的结果为:
i=2009,i++=2009;而在TC2.0下运行的结果为:
i=2010,i++=2009。
三、算术运算符的优先级和结合性
本章开篇时提到过,可以将一个表达式嵌套在另一个表达式中,另一个等价的说法就是可以用运算符去连接表达式。
当用基本算术运算符连接常量或变量时可以形成最简单的算术表达式,而常量和变量本身就是最简单的有值表达式,所以事实上可以用基本算术运算符去连接两个有值表达式,即expression1opexpression2,这里的expression1和expression2表示有值表达式,而op则代表5个基本算术运算符。
例如,a*b+2010(其中a、b为int变量)、3.5-2.0+d(d为double变量)。
1.运算符的优先级
当一个表达式中使用了多个运算符时,由运算符的优先级决定到底哪一运算先进行。
算术运算符的优先级如表3-1所示。
表3-1算术运算符的优先级表
运算符
优先级
++、--
2
*、/、%
3
+、-
4
所以在计算a*b+2010时,由于变量b左边的乘法运算符*的优先级高于右边的加法运算符+,所以该表达式应先执行乘法运算,后计算加法(将乘法运算的结果和常量2010相加)。
2.运算符的结合性
那么对于表达式“3.5-2.0+d”怎么计算?
因为变量d左右两边的运算符+和-的优先级是相同的。
由此可见,当某个常量或者变量左右两边的运算符的优先级相同的时,无法通过优先级来决定运算符执行的先后顺序,这时需要由结合性来判定运算顺序。
算术运算符的优先级和结合性如表3-2所示。
运算符
优先级
结合性
++、--
2
右结合
*、/、%
3
左结合
+、-
4
左结合
根据结合性,在计算3.5+d-2.0时,由于加法运算符+和减法运算符是左结合,即变量d先和左边的加法运算相结合,所以该表达式应先执行加法运算,后计算减法(将加法运算的结果和常量2.0相减)。
若想不受优先级和结合性的制约,人为地改变运算的先后顺序,则可以使用括号。
例如,对于表达式“a*b+2010”,若想强制先执行加法运算,则需对加法子表达式使用括号——a*(b+2009),对于表达式“3.5+d-2.0”,若想强制先执行减法运算,则需对减法子表达式使用括号——3.5+(d-2.0)。
3.复杂表达式的计算
在计算复杂表达式时,常常可以应用算符优先算法的基本思想——先从左往右扫描整个表达式,一旦发现表达式中某个变量或者常量左边运算符的优先级高于右边运算符的优先级时,就执行左边运算。
然后对经过化简的表达式按照上述过程继续化简,直到所有运算执行完毕为止。
【例3.7】若有定义语句:
ints=6;则表达式s%2+(s+1)%2的值为。
分析:
根据算符优先算法的基本思想,本例表达式中运算符的计算顺序如下:
s%2+(s+1)%2→0+(s+1)%2→0+7%2→0+1→1
【例3.8】算术运算符的优先级和结合性
#include
main()
{
inta=5,b=4;
printf("a=%d,b=%d\n",a,b);
printf("a+b%%3*a+b%%2/4=%d\n",a+b%3*a+b%2/4);
printf("a++/--b=%d\n",a++/--b);
printf("++a*a++=%d\n",++a*a++);
printf("++a*10+15/b++=%d\n",++a*10+15/b++);
printf("a=%d,b=%d\n",a,b);
}
3.3赋值运算符和赋值表达式
一、基本赋值运算符和赋值表达式的一般形式
1.基本赋值运算符
在第2章中,我们已经接触过对变量的赋值运算,它的作用是将数据存储在某个变量中(赋值运算实质上就是将数据写入到某个变量中)。
例如:
inti,j=-20,k;
i=j;
k=30;
当定义变量和对变量赋值在同一行进行时,称为对变量初始化。
2.赋值表达式的一般形式
我们既可以使用常量,也可以使用另一个变量的值对某个变量赋值,而常量和变量是最简单的有值表达式,所以赋值表达式的更一般的形式为:
变量=有值表达式。
说明:
(1)赋值运算符是双目运算符,出现在“=”左边的一定是个变量,右边的是一个有值表达
式,运算含义是将有值表达式的结果存入左边的变量中。
(2)赋值运算的结果是经过赋值以后“=”左边的变量值。
(3)我们已经学过的有值表达式包括:
常量、变量、算术表达式(包括自增、自减表达式)
和赋值表达式。
假设有如下变量定义:
inta=2,b=4,c,d;则:
c=a+b、c=a++、d=--b、
d=c=a等都是赋值表达式。
(4)赋值运算符的优先级在C语言所有运算符中排倒数第二(仅高于逗号运算符)。
(5)赋值运算符的结合性是右结合。
【例3.9】基本赋值运算测试。
#include
main()
{
inta=3,b=-4,c,result;
result=a+b;
printf("%d+%d=%d\n",a,b,result);
printf("%d\n",c=b);
printf("%d\n",c=c+1);
a=b=c+-5;
printf("a=%d,b=%d,c=%d\n",a,b,c);
a=(b=c)+-5;
printf("a=%d,b=%d,c=%d\n",a,b,c);
}
说明:
(1)表达式“c=c+1”相当于“++c”,而不是“c++”!
(2)要根据运算符的优先级和结合性,应用算符优先算法的基本思想去计算带有多个运算符的复杂表达式。
二、复合赋值运算符和复合赋值表达式
C语言进一步将算术运算符、位运算符同基本赋值运算符结合起来构成复合赋值运算
符。
复合赋值运算符分为算术复合赋值运算符和位复合赋值运算符两类,具体如下:
+=、
-=、*=、/=、%=、&=、|=、^=、<<=、>>=。
复合赋值表达式的基本形式为:
变量名op=有值
表达式,op是指5个基本算术运算符(+、-、*、/、%)和5个位运算符(&、|、^、<<、>>)。
计算复合赋值表达式时可进行等价转换:
“变量名op=有值表达式”等价于“变量名=
变量名op有值表达式”。
例如,inta=5;则a+=3等价于a=a+3,intx=2,y=3;则x*=y+8
等价于x=x*(y+8)。
复合赋值运算符的优先级、结合性和基本赋值运算符相同。
【例3.10】若a是int变量,且a的初值为6,则计算表达式后a的值为。
a+=a-=a*a
说明:
本例的计算过程如下:
a+=a-=a*a→a+=a-=36→a+=-30(a=-30)→-60(a=-60)。
【课内思考题3.1】设有说明语句:
intk=7,x=12;则以下能使值为3的表达式为。
A)x%=(k%=5)B)x%=(k-k%5)
C)x%=k-k%5D)(x%=k)-(k%=5)
【课内思考题3.2】若x和n均是int变量,且x和n的初值均为5,则计算表达式“x+=++n”后x的值为,n的值为。
【课内思考题3.3】若有以下定义intm=5,y=2;则计算表达式y+=y-=m*=y后y的值是。
三、根据变量的数据类型赋值
【例3.11】赋值时要注意目标类型的取值范围。
#include
main()
{
shortsi=32800;
printf("si=%d\n",si);
}
说明:
本例程序的运行结果为“si=-32736”。
注意到变量si是short类型,通常占2个字节,取值范围-32768~32767。
现在将常量32800赋给变量si,显然超过了short类型的表示范围。
【课内思考题3.4】分析以下程序的运行结果:
#include
main()
{
shortsi=-32800;
printf("si=%d\n",si);
}
3.4类型转换运算
一、普通算术类型转换规则
C语言规定,当不同数据类型的操作数参加同一运算时,必须将它们统一成同一数据类型,也就是要将其中一个操作数的数据类型转换成另一个操作数的数据类型。
在进行类型转换时,应尽量遵照普通算术类型转换规则,这样才不会丢失运算结果的精度。
下面引用1988年C语言的美国国家信息系统标准中关于这一个规则的详细内容。
如果任何一个操作数为longdouble类型,则将另一个操作数转换为longdouble类型。
否则,如果任何一个操作数为double类型,则将另一个操作数转换为double类型。
否则,如果任何一个操作数为float类型,则将另一个操作数转换为float类型。
否则,同时对两个操作数进行整型提升;如果任何一个操作数为unsignedlongint类型,则将另一个操作数转换为unsignedlongint类型。
(注:
总能将一个有符号数(补码)理解成一个无符号数。
也即同一类型的无符号数可以表示有符号数,比如unsignedlong能表示long)
否则,如果一个操作数为longint类型且另一个操作数为unsignedint类型,则结果依赖于longint类型是否可以表示所有unsignedint类型的值。
如果可以,则将unsignedint类型的操作数转换为longint;如果不可以,则将两个操作数都转换为unsignedlongint类型。
否则,如果一个操作数为longint类型,则将另一个操作数转换为longint类型。
否则,如果任何一个操作数为unsignedint类型,则将另一个操作数转换为unsignedint类型。
否则,将两个操作数都转换为int类型。
从上述规定不难看出,普通算术类型转换规则的实质,是将能表示数据范围较小的数据类型,向能表示数据范围较大的数据类型转换。
【例3.12】若有以下变量定义:
doubled=-128.5;
floatf=32.25;
unsignedlongul=298UL;
longl=-20L;
unsignedintui=125u;
unsignedshortintusi=56;
charch;
按照普通算术类型转换规则说明以下表达式正确的类型转换:
d+ul、1.234+f*l、ui+ch、usi+’#’、ui+l(c-free中)、ui*l(tc中)。
二、类型转换
根据类型转换时是否使用类型转换运算符,可将类型转换分为隐式类型转换(自动类型转换)和显示类型转换(强制类型转换),其中在进行强制类型转换时用户需要使用类型转换运算符。
1.隐式类型转换
隐式类型转换过程中如果违背了普通算术类型转换规则,一个好的编译器会向用户发出warning(警告信息)。
【例3.13】测试隐式转换语法。
#include
main()
{
floaty,z=242.5f;
unsignedx=2;
shorts=4;
y=10+'b'+5.7*x+z/'a'-s*12.5;
printf("y=%f",y);
}
说明:
(1)本例程序第7行的复杂表达式“y=10+'b'+5.7*x+z/'a'-s*12.5”计算过程如下:
(2)本程序在编译时产生了一个warning,原因在于,程序中的表达式的最终类型为double,而存储该表达式值的变量y的类型是float,虽然编译器允许double到float的隐式转换,但这一转换显然违背了普通算术类型转换规则,存在精度丢失的风险!
2.强制类型转换
强制类型转换的语法格式是在圆括号中给出想要转换的目标类型,随后紧跟待转换的常量、变量名或待转换的表达式。
例如:
doublex=3.6,y=-2.8;
intnx1,nx2,nx3;
nx1=(int)x;
nx2=(int)(x+y);
nx3=(int)x+y;
说明:
(1)强制类型转换通过截断小数部分来把一个浮点值转换为整型,所以变量nx1的值为3。
虽然经过强制类型转换,但变量x的数据类型和值都未发生变化(值仍然为3.6)。
(2)表达式“(int)(x+y)”是把x+y的结果转换为int,所以该表达式的结果为0。
(3)类型转换运算符用来连接一个常量、变量或一个表达式,所以是单目运算符。
它的优先级在C语言所有运算符中排第二(和++、--相同),结合性是右结合。
所以在计算表达式“nx3=(int)x+y”时,先对x的值进行类型转换得到3,然后和变量y的值相加,进行隐式转换,得到和为0.2,最后执行赋值运算,变量nx3的值就是0.2。
【例3.14】测试显式转换语法。
#include
main()
{
doubled=123.456;
inta=17.7,b=8;
printf("(int)3.1415926=%d\n",(int)3.1415926);
printf("(int)d=%d\n",(int)d);
printf("d=%f\n",d);
printf("d+10=%f\n",d+10);
printf("(int)(d+10)=%d\n",(int)(d+10));
printf("17/8=%d\n",a/b);
printf("17/8=%f\n",(double)a/b);
printf("%f\n",(double)a/b-a/b);
}
说明:
(1)在将常量17.7赋给变量a时,编译器执行隐式类型转换,变量a的值为17。
在赋值运算中如果使用了隐式类型转换,不论是否会违背普通算术类型转换规则,编译器一律将赋值运算符号右边的运算对象的值,转换成赋值号左边的变量类型。
(2)程序的第6行和第7行通过强制类型转换,分别在屏幕上打印常量3.1415926的整数部分3和变量d的值的整数部分3。
(3)接着在程序的第8行将变量d的值打印出来,这样就能看出强制类型转换对变量d的值是否会产生影响。
(4)程序第9行在计算表达式“d+10”的结果时,,编译器要先进行隐式类型转换,根据普通类型转换规则,将10转换成double常量10.0,再进行加法运算,得到和133.456,最后打印结果。
(5)两个整型数据相除以后的结果是整数商,例如程序第10行表达式“a/b”的结果为2。
如果想同时得到商的小数部分,就可以对其中任何一个整型数据进行强制类型转换,例如“(double)a/b”,结果2.125。
如果仅想得到商的小数部分呢?
只需要用完整商减去商的整数部分即可,也就是“(double)a/b-a/b”。
(6)如果试图将数据从一种类型强制转换成另一种数据类型,而又超出了目标类型的表示范围,结果就会被截断为成一个完全不同的数值。
例如下面这个程序的运行结果为-32736。
#include
main()
{
printf("%d\n",(short)32800);
}
3.5逗号运算符和位运算符
一、逗号运算符和逗号表达式
C语言提供了一种特殊的运算符:
逗号运算符,通过逗号运算符可以将两个表达式连接起来形成逗号表达式:
表达式1,表达式2。
所以逗号运算符是双目运算符。
当然可以用逗号运算符去连接两个逗号表达式:
表达式1,表达式2,表达式3,表达式4。
将上述过程推广下去,就得到逗号表达式的更一般形式:
表达式1,表达式2,…,表达式n。
逗号运算符在C语言所有的运算符中优先级最低,结合性是左结合,所以在计算逗号表达式时先计算逗号左边的表达式,再计算逗号右边的表达式,整个逗号表达式的结果是逗号右边表达式的值。
【例3.15】分析下面的逗号表达式的计算结果。
设有如下变量定义:
inta=10,x;
(1)a=3*5,a*4
(2)(a=3*5,a*4),a+5(3)x=(a=3,6*3)(4)x=a=3.6*a
二、位运算符和位运算表达式
在处理整型数据(包括字符数据)时,通过C语言可以直接对整型数据的位模式(二进制补码)中的各个位进行操作。
C语言提供给用户使用的位运算符包括:
按位与(&)、按位或(|)、按位取反(~)、按位异或(^)、左移(<<)、右移(>>)六种,其中位反运算符~是单目运算符,其余的运算符都是双目运算符。
另外所有的双目位运算符还能和赋值运算符结合成复合赋值运算符。
有关位运算符的优先级和结合性请参见下面的“C语言运算符优先级和结合性”表。
1.位与、
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言程序设计 第三 运算 表达式
![提示](https://static.bdocx.com/images/bang_tan.gif)