算术表达式
知识点:运算符号的优先级别;强制类型转换的使用;
重要程度:★★★★
1、算术运算符与算术表达式
1、在C语言中,有下列五个基本的算术运算符:+、-、*、/和%,依次表示加、减、乘、除、求
余运算。(考得最多的是/ 和%符号!!!)
2、求余运算符%的运算对象只能是整型,即%左侧的被除数与右侧的除数都只能为整型值。
求余得到的运算结果的符号与被除数相同。(3%1.2错了)
如:12%9运算结果为3,12%-9的运算结果也为3。
-12%9运算结果为-3,-12%-9的运算结果也为-3。
3、求余就是求余数,而不是求商,这点总是容易被弄混淆。
² 想一想:3%9运算结果为多少??(结果为3而不是0)
4、1/2得到的数据是为0的,这个原则是当除号“/“左右两边都为整数的时候,我们遵守取整丢小数的原则。那么如果希望1和2相除得到0.5,我们就可以用1.0/2,或者1/2.0,或者1.0/2.0都可以实现。
先面通过一个具体例子的分析,我们来彻底搞清楚算术运算符的运算规则。
例1:试求 1.6+3/2*1.2-3/2.0 的值
步骤: |
计算过程: |
说明: |
第一步: |
1.6+1*1.2-3/2.0 |
根据运算优先级和结合的顺序,先算3/2,注意到它们为整型数据相运算,因此结果应为整数1,而不是1.5。 |
第二步: |
1.6+1.0*1.2-3.0/2.0 |
1*1.2为整型和实型数据相运算,因此,会把整型数据1转换为对应的实型数据1.0,再与1.2进行运算。同理,3变成3.0 |
第三步: |
1.6+1.2-1.5 |
分别计算出 1.0*1.2 和 3.0/2.0 的结果 |
第四步: |
2.8-1.5 |
同一优先级的运算,从左到右依次进行 |
第五步: |
1.3 |
结果为1.3,而不是1.9 |
下面,大家自己算算,表达式3.6-5/2+1.2+5%2的值应该是多少?
A)4.3 B)4.8 C)3.3 D)3.8
分析:根据表3列出的算术运算符优先级,本题目应先计算5/2与5%2得到2和1,然后再计算3.6-2+1.2+1,得到答案D。
2、强制类型转换
在进行算术运算时,如果希望将某一运算量转换成指定的类型,则可以利用强制类型转换符。
强制类型转换表达式为:(类型名)表达式
其中,“(类型名)”是强制类型转换符,它将右边表达式的类型转换为括号中的类型。
强制类型转换并不会改变右边表达式的值,(类型名)表达式 这个整体产生了一个临时值。
例:有如下代码:
float a=3.8;
int b;
b=(int)a;
这段代码把a强制转化为整型数据3(注意C语言里的强制转换都是截取,而不是四舍五入),并把这个值3赋给整型变量b。注意,此时a的值仍然是3.8。
强制转换只控制其后的一个数据
例:(int ) a+b和(int ) (a+b)不同:
前者是把a强制转换为整型,再把这个临时的整型值和b作运算。
后者是先计算a+b,之后把它们的值做整体的强制转换。
强制转换需要注意的几点:
1) 类型名外的()必不可少
2) 强制转换控制其后的一个数据
3) 强制类型转换并不会改变右边表达式的值
第六节 赋值表达式
知识点:赋值表达式的运算;复合赋值表达式的运算;自加和自减;
重要程度:★★★★★
1、赋值运算符和赋值表达式
int a = 12;
它的含义是将赋值运算符右边的表达式的运算结果赋值给左边的变量。
说明:
1)赋值运算符左边必须是单个变量。例如x+1=3在数学上虽然是正确的,可是在C语言中却
是错误的,不能将一个常量赋值给一个表达式。
2)赋值运算会将左边变量的值用右边表达式的值来代替,右边的值不会改变。
例如,int x=3,y=5;
x=y+1;
以上代码先将x初始化为3,将y初始化为5。执行完赋值语句x=y+1;后,变量x的值被y+1覆盖掉,即x的值变成了6,变量y的值不会改变。
用盒子理论来说就是,先定义了两个盒子,分别叫做x盒子和y盒子,x盒子装的是整数3,y盒子装的是整数5。之后把x盒子所装的内容改成y盒子的内容加1,也就是6。这样,x盒子中装的就是6了,以后再要使用x,都是用的新值6。而以前x装过什么值现在再也不知道了。
3)赋值表达式的值是赋值号左边变量被赋值后的值。
例如:x=0整个赋值表达式的值是变量x被赋值之后的值,也就是说这个表达式的值为0。
4)可以将赋值表达式的值再赋值给变量,形成连续赋值运算。(学会分析过程)
例如,x=(y=25)是一个连续赋值表达式。由于赋值表达式的结合形式是从右到左,因此可以简写为x=y=25,它表达的含义是将25赋值给变量y,然后将表达式y=25的值赋值,即变量y的值赋给变量x,结果使变量x和y的值都变为25。
5)虽然可以连续赋值,但是不能连续初始化。(考试重点)
例如:int x=y=25; 就是错误的。
对于int x=y=25;我们会先计算y=25,此时,y并没有定义,而是在直接使用,所以就会报错。
如果我们把上面的连续初始化改成:int y; int x=y=25; 这样就没有错了。
6)赋值运算符不同于数学上的“等号”。(C语言中“=”表示赋值,“= =”表示等号)
因为赋值运算符的操作是将赋值号右边的表达式的值赋给左边的变量。它是单方向的操作。例如在数学中,i=i+1不成立,但在赋值表达式中却是成立的,它表示将变量i的值增加1之后得到的结果赋值给变量i,因此,该表达式的含义是使变量i的值增加1。
7)如果赋值号两边的运算对象类型不一致,则系统会自动进行类型转换。
8)自动类型转换的实例:int a=3.6;
赋值号左边的变量类型是整数,右边的值是实数,因此将右边的值转换成整数。3.6转换成整数后是3,因此a的值被赋为了3。
注意:实数转换成整数的方法是截取而不是四舍五入,因此直接把小数点后的数据去掉就行了。
2、复合赋值表达式(掌握如何计算即可)
在C语言中,可以将算术运算符与赋值运算符组合在一起组成复合赋值运算符。它们是:+=,-=,*=,/=,其使用方法及具体的运算规则如下:
表达式n+=100等价的表达式为:n=n+100
表达式n-=2*n等价的表达式为:n=n-2*n
表达式n*=m+1等价的表达式为:n=n*(m+1)
表达式n/=m+1等价的表达式为:n=n/(m+1)
上述四种复合赋值运算符的运算优先级与赋值运算符的优先级相同(优先级都非常低),运算方向均为自右向左。
想一想:n+=10和n+10有什么区别?区别在于前者n本身的值改变了,而后者n的值没有改变。
例1: 已知变量n的初始值为8,计算表达式n+=n*=n-2的值。(经典考题)
分析:表达式中有两个复合赋值运算符:+=和*=。它们优先级相同,运算方向均为自右向左。因此,运算的步骤如下:
(1)先计算最右边表达式n-2的值为6;
(2)再计算n*=6,该表达式等价n=n*6,将n中的值8乘以6,得到48,并赋值给n,因此变量n的值为48,表达式n*=n-2的值为48;
(3)最后计算n+=48,该表达式相当于n=n+48。因为上一步计算出n的值为48,所以n+48的值为96,即n的值最终为96。
通过计算,表达式n+=n*=n-2的值为96。
例2:int a=5,b=6,c=2;
c *=a+b;
请问:c的值最终是多少?
错误的算法: c=c*a+b;得到的是16。
正确的算法: c=c*(a+b);得到的是22。
自加表达式
1、自加与自减运算符(超级重点)
如何让一个变量自身的值加1?通过之前的学习,我们知道a=a+1; 和 a+=1; 都可以实现。而我们将要讨论的a++和++a同样可以实现这样的效果。
自加、自减运算是一种赋值运算。
既然a++和++a写法上有区别,那么它们应该有所不同。这里仅就++运算符进行说明,--运算符有类似的结论:
a++和++a的相同处:对于变量a而言,它们都是让a的值加1。
a++和++a的不同处:( ++a)、(a++)是两个自加表达式,所以这两个表达式本身就有数值,只是++a,a++两个的表达式的数值不同。
自加表达式的核心理解
|
² 遇到a++,就看成a,等这部分执行结束后,再让a的值加一。(加号在后,则先使用后自加)
² 遇到++a,则把a的值先加一,之后再使用加过一后的值。(加号在前,则先自加后使用)。
例如有以下代码(通过以下代码,学会分析a++和++a的执行过程):
int a=3,b;
b=a++;
这段代码执行完后,b的值为3,a的值为4。
对于语句b=a++; 按照以上所说,我们就看成b=a; 此时a值为3,因此赋值后b的值也为3。等这部分执行结束后,再让a的值加一。因此,整个这段代码结束后,b的值为3,a的值为4。
----------------------------------------------------------------------------------------------------------------------------------
int a=3, b;
b=++a,代码发生了变化,那么执行完后,a和b的值分别为多少呢?
对于语句b= ++a; 按照以上所说,我们把a值先加一,得到a的值为4。之后赋值给b。因此,整个这段代码结束后,a、b的值都为4。
|
说明:
补充考点:
1)增量运算符的运算对象只能为单个变量,不能是常量或是表达式。例如:++3、++(i+1)
都是不合法的增量表达式。
2)不论“++”在变量的前面还是在变量的后面,对于变量本身都具有“增加1”的相同效果。
例如i++、++i两个增量表达式运算后变量i的值都是增加1。
3)自加、自减运算符的结合方向是“从右到左”。
例如有如下代码:
int y,x=3;
y=-x++;
负号“-”与自加运算符“++”具有相同的运算优先级,但是根据“从右到左”的结合方向,那么应该先计算x++,而x++可以先看成就是x。取其负值3赋给y,那么y的值就为-3,这部分执行结束了,x的值再加一,所以这段代码结束后,x的值为4,y的值为-3。
4)在使用“++”运算符时,变量应该有个确定的值。例如:int a; a++; 就是错误的。因为刚定
义好的a值不确定。让一个垃圾值自加一没有任何意义。
经典考题:
例1: 有以下定义语句:double a,b; int w; long c;
若各变量已正确赋值,则下列选项中正确的表达式是
A)a=a+b=b++ B)w%((int)a+b) C)(c+w)%(int)a D)w=a%b;
分析:答案C正确。
选项A是一个连续赋值表达式,先将表达式b++的值赋值给表达式a+b,因为赋值语句的左边只能是变量名称,因此这时会出错。
选项B是一个求余运算符连接起来的两个运算对象,除数((int)a+b)看起来比较复杂,它先将双精度类型变量a的值强制转换为整型,然后再与双精度类型变量b求和,得到的值的类型仍为双精度类型,也就是说除数是一个实数而不是整数,因此不能使用%运算符,所以答案B错误。
选项C的被除数是两个整型数相加,运算结果为整型,除数为(int)a,也为整型,答案C正确。
选项D中a%b错误。
例2 有以下程序
main()
{ int m=12,n=34;
printf("%d%d",m++,++n);
printf("%d%d ",n++,++m);
}
程序运行后的输出结果是
A)12353514 B)12353513 C)12343514 D)12343513
分析:在第一个printf输出语句中,计算表达式m++时,其值为变量m的初始值,即12,因为执行了表达式m++,变量m的值增加1,因此m的值变为13。计算表达式++n 时,其值为变量n的初始值增加1,即35,因为计算了表达式++n,因此变量n的值增加1,为35。在第二个printf中,计算n++时,其值为n的初始值,即上一次计算得到的35,因为计算了n++,变量n的值增加1。计算++m时,其值为变量m的初始值增加1,即使上一次计算得到的m的值加上1,为14。因此本题答案为A。
逗号表达式
5、逗号运算符和逗号表达式
1、在C语言中,逗号除了做分隔符,还可以作一种运算符——逗号运算符。用逗号运算符把两个或两个以上的表达式连接起来,可以构成一个新的表达式,即逗号表达式。例如:
x=5,y=6,z=7 整个(x=5,y=6,z=7)是逗号表达式,他的数值等于7,
2、逗号运算符是级别最低的运算符号,比赋值还要低。
3、逗号运算符具有从左到右的结合性,即先计算第一个表达式,然后计算第二个表达式,直到最后一个表达式。最后一个表达式的值就是整个逗号表达式的值。上述的逗号表达式的值就是表达式z=7的值7。
x=5,y=6,z=7 是个逗号表达式,它的数值为7。x的数值为5。
x=(5,y=6,z=7) 是个逗号表达式,它的数值为7,x的数值为7。
.
例1: 有以下程序
main( )
{ int a1=3,a2=9;
printf("%d ",(a1,a2));
}
以下叙述中正确的是
A)程序输出3 B)程序输出9
C)格式说明符不足,编译出错 D)程序运行时产生出错信息
分析:函数体中首先变量初始化,变量a1、a2的值分别为3和9,接下来的printf输出语句中,要输出的项是(a1,a2),在此要明白输出项是一个逗号表达式就不会选错答案。逗号表达式a1,a2的值就是a2的值,因此本题的答案为B。
请注意它与printf("%d ",a1,a2)的区别。
例2: 有以下程序(经典考题)
main( )
{ int x,y,z;
x=y=1;
z=x++,y++,++y;
printf(“%d,%d,%d ”,x,y,z);
}
程序运行后的输出结果是
A)2,3,3 B)2,3,2 C)2,3,1 D)2,2,1
分析:函数体中首先定义了三个整型变量x,y和z,接下来,对变量x和y赋值为1。然后,仔细分析语句z=x++,y++,++y;,因为逗号运算符在所有运算符中的优先级最低,因此赋值表达式应该先于逗号表达式计算,所以上述逗号表达式语句由三个赋值表达式组成:z=x++、y++和++y。按逗号表达式的计算规则,从左至右依次计算每个表达式,故应先计算x++,并将其值赋给变量z,z的值为1,因为计算了x++,x的值增加1,变为2;计算了y++和++y,变量y的值应增加2,变为3。最后,程序
输出x,y,z的值应为2,3,1。本题答案为C。
补充:
int a=1,x;
x= (a++,a++,++a)后,x的数值为多少? x为3.
int a=1,x;
x= a++,a++,++a后,x的数值为多少? x为1