- C++程序设计基础(上)
- 周霭如 林伟健编著
- 711字
- 2020-08-28 09:48:04
1.5 表达式
表达式是指由数据和运算符组成,按求值规则,表达一个值的式子。表达式可以很简单,例如,一个常数、一个常量或变量名,也可以很复杂,包含各种运算量、运算符等。C++语言的表达式使用相当灵活,功能很强。按照运算性质,表达式可以分为:算术表达式、逻辑表达式、赋值表达式、条件表达式和逗号表达式。
我们结合表达式的种类,讨论各种运算符的作用和表达式的应用规律。有些运算符将在后续有关章节中出现的时候介绍。
1.5.1 运算符
运算符是以简洁的方式表达对数据操作的符号。C++运算符主要有:
算术运算符 + - * / % ++ -- 关系运算符 > < == >= <= != 逻辑运算符 ! && || 位运算符 << >> ~ | ^ & 赋值运算符 = 及扩展的复合运算符 条件运算符 ?: 逗号运算符 , 指针运算符 * & 求字节运算符 sizeof 强制类型转换符 类型符 分量运算符 . -> 下标运算符 [] 其他 () :: new delete
运算符又称为操作符。不同的运算符要求不同数量的操作数。由操作符和操作数构成表达式。其中,操作数可以是常量、变量或表达式。根据要求操作数的个数不同,运算符可以分为一元运算符、二元运算符和三元运算符。
① 一元运算符。一元运算符只要求有右操作数,表达式形式为:
Op 右操作数 或 左操作数 Op
其中,Op表示运算符。+,-,!,++都是一元运算符。例如:
-123 +500 !b a++
② 二元运算符。二元运算符要求有左、右操作数,表达式形式为:
左操作数 Op 右操作数
+,-,*,/,>,<等都是二元运算符。例如:
i+1 a*3 x>y
③ 三元运算符。C++语言只有一个三元运算符,就是条件运算符。表达式形式为:
操作数 1 ? 操作数 2 : 操作数 3
例如: a ? b : c
一个复杂表达式会包含多个运算符。运算符之间的运算次序由各运算符的优先级(优先关系)和结合性决定。
表达式中的运算符按优先级从高到低运算,带括号的内层优先,同级运算符从左到右运算,见表1.3。这些规则与习惯的数学规则一致。
表1.3 常用运算符的功能、优先级和结合性
从左至右结合的运算符,首先计算左操作数,然后计算右操作数,最后按操作符求值;从右至左结合的运算符,则首先计算右操作数,然后计算左操作数,最后按操作符求值。
例如: (a+b) * (x-y)
其中,“*”运算符从左至右结合,首先计算左操作数(a+b),然后求右操作数(x-y),最后作*运算。
又如: - (x+y)
其中,一元“-”从右至左结合,首先计算右操作数(x+y),然后对结果求负。
本章讨论算数运算和逻辑运算。位运算将在第5章中讨论。
1.5.2 算术表达式
1.基本运算
算术表达式由算术运算符和操作数组成,结果值是算术值。基本算术运算符有:
+ 加法,或一元求正 / 除法 - 减法,或一元求负 % 求模(求余) * 乘法 sizeof 求存储字节
“求模”运算是计算两个整数相除的余数。例如:
7%4 //等于3 5 % 21 //等于5 12 % 2.5 //错误,操作数不能为浮点数
sizeof求数据类型占内存的字节数。例如:
int a; sizeof(a) //等于4,在16位机上等于2 sizeof(int) //等于4 sizeof(26756) //等于4 sizeof(double) //等于8 sizeof(0.25) //等于8
2.运算符的多义性
作用于基本数据类型的算术运算符意义很明确,但要注意,一些符号意义与上下文有关。
例如,“*”号在以下不同语句中有不同的意义:
int a = 35; int*p=&a; //指针类型说明符 a=a*4; //算术乘 *p=5**p; //第1,3个“*”是间址访问,取内容;第2个“*”是算术乘
以上注释中说明了各个“*”号的意义。表达式:
5 * *p
两个“*”中间的空格可以不写。系统可以正确运行,这是因为间址访问符是右结合运算符,而且优先级高于算术乘,编译器能够识别。程序员为了明确起见,可以写为:
*p = 5 * (*p )
又如: -5.6+3.2
不能理解为: -(5.6+3.2)
因为一元负运算符优先级高于加运算符,而且为右结合,所以解释为:
(-5.6)+3.2
3.自增和自减
在程序中,我们经常会用到以下操作:
i = i+1和i = i-1
这两个操作分别称为变量的自增和自减。C++用“++”和“--”运算符描述这两种常用运算,见表1.4。
表1.4 自增和自减
后置式和前置式在独立使用的时候没有区别。但当它作为子表达式时,会对其他变量产生不同的影响。例如:
int a = 0, b = 0, i = 0; a=++i; //a为1,i为1 b=i++; //b为1,i为2
执行第2行语句时,++i是前置式的,先自增,然后把i的值赋给 a。
而执行第3行语句时,i++是后置式的,先读出i的值赋给b,然后自增。虽然“++”的优先级高于“=”,但这里语义起作用。
又如: c = a++ + ++b;
与以下几种书写方式等价:
① c = (a++) + (++b);
② b = b+1; c = a+b; a = a+1;
③ b ++; c = a+b; a++;
④ ++b; c = a+b; ++a;
再如: c = ++a + ++b;
与以下几种书写方式等价:
① c = (++a) + (++b);
② b = b+1; a = a+1; c = a+b;
③ b++; a++; c = a+b;
④ ++b; ++a; c = a+b;
显然,自增运算符的连用可读性较差,没有相当的熟练程度最好不用。
4.类型转换
表达式是表达一个值的式子,算术表达式的值的类型由操作数的类型决定。
① 如果运算符左右操作数类型相同,则运算结果也是相同类型。例如:
6+5 //结果为整型值11 2/4 //结果为整型值0。因为左右操作数都是整数,做整除
② 如果运算符左右操作数类型不同,则首先把类型较低(存储要求、示数能力较低)的数据转换成类型较高的数据,然后运算。例如:
cout << 3 + 'A' << endl;
把1字节长的char类型字符'A'转换成1个字长的int类型65,输出:
68
又如:
2.0/4 //结果为浮点型值0.5
③ 赋值的类型转换。当把一个表达式的值赋给一个变量时,系统首先强制把运算值转换成变量的类型,然后执行写操作。这种强制类型转换是易于理解的,因为被赋值的对象类型已经定义,必须把类型不一致的右操作数转换后才能写入指定存储单元。
【例1-10】类型转换测试。
#include<iostream> using namespace std; int main() { int a; char c; double x; a=2.0/4; //把0.5赋给a
x=2.0/4; //把0.5赋给x cout << a << '\t' << x << endl; a=3+'A'; //把68赋给a c=3+'A'; //把68转换为字符'D',赋给c cout << a << '\t' << c << endl; cout<<3+'A'<<endl; //表达式值为整型 }
程序运行结果:
0 0.5 68 D 68
④ 强制类型转换。C++可以用类型符对表达式值转换成指定类型,一般形式为:
(类型) (表达式)
或 (类型) 表达式
或 类型 (表达式)
例如:
(int)(x+y) //把x+y的结果转换成整型 (char)70 //把整数70转换成字符 'F' double(a)+y //把a的值转换成double类型再加上y的值
注意: (double)(2/4)
把2/4的运算结果转换成double,等于0。而
(double)2/4
先把2强制转换为double型,然后按照运算类型转换的原则,自动把4转换为double型,最后相除的结果等于0.5。
赋值时的类型转换和用类型符实现的类型转换是强制性的,所以,要把低类型数据转换成高类型时,一般不会发生什么问题。反之,把高类型数据转换成低类型,就有可能引起数据错误或丢失。这是程序员应该特别注意的。
1.5.3 逻辑表达式
逻辑表达式用于判断运算,结果值只有两个:判断成立,则为逻辑“真”(true);否则为“假”(false)。C++用true或1值表示计算结果为逻辑真,用false或0值表示逻辑假。而在程序运行中,即表达式求值过程中,非0值都作为逻辑真。
构成逻辑表达式的运算符有关系运算符和逻辑运算符。
1.关系运算
关系运算即比较运算,用于算术值比较。C++的关系运算符有:
< 小于 <= 小于等于 > 大于 >= 大于等于 == 等于 != 不等于
前4种比较运算符的优先级高于“==”和“!=”。
例如,设a=1,b=2,c=3,则
a<=b //逻辑真,值为true(1) (c>b)==a //逻辑真,值为true(1) b!=1/c //逻辑真,值为true(1) a+b>c //逻辑假,值为false(0)
注意,如果想用表达式
c > b > a
表达“c的值大于b的值,b的值大于a的值”,将得到错误的判断结果。按照运算符左结合的原则,首先计算 c>b,值为 true(1),然后用整型值 1 计算1>a,结果值为 false(0),失去逻辑判断意义。导致错误的原因是,C++表达式在运算过程中用 0 或 1 表示逻辑值。C++编译器会对这种表达式提示警告(warning)。正确的方法是用逻辑表达式:
c > b && b > a
字符值用ASCII码进行比较:
'A'>'B' //值为false(0) 50<'D' //值为true(1)
2.逻辑运算
逻辑运算用于判断多种逻辑情况在某些条件组合之下的结果。C++的逻辑运算符有:
&& 逻辑与 || 逻辑或 ! 逻辑非
“&&”和“||”是二元运算符,“!”是一元运算符。
“逻辑与”只有在左、右操作数都为true(非0)时,结果才为true。
“逻辑或”只要左、右操作数中有一个为true(非0),结果就为true。
“逻辑非”表示取操作数逻辑相反值。
表1.5为基本逻辑运算的真值表,其中列出了左操作数a和右操作数b取不同组合时,各种逻辑运算的结果。
表1.5 逻辑真值表
“!”运算符优先级高于“&&”,“&&”优先级高于“||”。在一个表达式中,可能包含算术运算、关系运算和逻辑运算,优先级从高到低为:
! → 算术运算符 → 关系运算符 → && → ||
例如:
a>b&&b>c 相当于 (a>b)&&(b>c) a==b||c==d 相当于 (a==b)||(c==d) !a||a>b 相当于 (!a)||(a>b)
算术值和字符值也可以参与逻辑运算:
'x'&&'y' 值为1 5>3||2&&1-!0 值为1
【例1-11】写出描述点A(x,y)落在图1.10中灰色部分(不压线)的C++表达式:
图1.10 用关系表达式描述落点
-2<x && x<2 && -2<y && y<2 && x*x+y*y>1
请读者分析这个表达式的运算次序。
1.5.4 赋值表达式
前面,我们已经使用过赋值表达式了。赋值表达式的作用是把数据值写入变量。C++赋值表达式的一般形式为:
变量 = 表达式
由于C++使用“赋值表达式”的概念,赋值号右边“表达式”也可以是赋值表达式,使得赋值操作可以拓展。
例如: a = b = 10
相当于: a = ( b = 10 )
表达式b=10的值为10,b的值等于10,把10赋给a。也可以用赋值号右结合来理解,首先把10赋给b,然后把b的值赋给a。但是,
( a = b ) = 10
就不一样了。括号改变了执行顺序,首先应执行a=b,把b的值写入a,表达式的值确定于a,然后执行a=10。上式对a做了两次写操作,对b做了一次读操作。
【例1-12】赋值表达式测试。
#include <iostream> using namespace std; int main() { int a,b; a = b = 10; cout << a << '\t' << b << endl; ( a = b ) = 5; cout << a << '\t' << b << endl; }
程序运行结果:
10 10 5 10
赋值表达式又称为“左值表达式”,因为表达式的值确定于一个存储单元,所以可以放在赋值号的左边,也可以放在赋值号的右边。而
3 + 7
这样的表达式,虽然能够表达整型值10,但不能确定于一个存储单元,所以只能放在赋值号的右边,称为“右值表达式”。
例如:
a=b=3+7 //正确 3+7=a //错误 a=b+3=10 //错误 (a=b+3)=10 //正确
C++还有一批用于简化代码的复合赋值运算符:+=、-=、*=、/=、%= 等。一般形式为:
A Op=B 等价于 A=A Op B
即
a+=b 等价于 a=a+b a-=b 等价于 a=a-b a*=b 等价于 a=a*b a/=b 等价于 a=a/b a %=b 等价于 a=a%b
例如:
a+=10 等价于 a=a+10 b*=2+3 +优先级高于*=,等价于 b=b*(2+3)
1.5.5 条件表达式
条件表达式由条件运算符和操作数组成,根据逻辑值决定表达式的求值。
条件表达式形式为:
操作数 1 ? 操作数 2 : 操作数 3
执行过程是:首先对“操作数 1”求值,其值非 0 时,表达式的值为“操作数 2”的值;否则,表达式的值为“操作数3”的值。
“操作数1”通常是判断的条件表达式或逻辑表达式。例如:
a > b ? a : b
表达式的功能是取a、b中的大值。要把这个值赋给变量max,可以用以下语句表示。
max = a > b ? a : b;
“操作数1”也可以是其他类型的表达式,因为C++把算术值也视为逻辑值。例如:
4+2 ? 0 : 1
是一个合法的表达式。当然,这个式子没有什么意义。
如果“操作数 1”包含程序运行时动态变化的数据,那么,表达式会起到简单的控制作用。例如:
x>y?x-y:y-x //求|x-y|
条件运算符按右结合方式匹配。例如,求a、b、c中的最大值,用条件表达式可以表示为:
a>b ? a>c ? a : c : b>c ? b : c
相当于:a>b ? (a>c ? a : c) : (b>c ? b : c)
【例1-13】求3个整数中的最大值。
#include <iostream> using namespace std; int main() { int a,b,c,max; cin>>a>>b>>c; //输入数据 max=a>b?a>c?a:c:b>c?b:c; //求最大值 cout << "max = " << max << endl; }
1.5.6 逗号表达式
用逗号连接起来的若干个表达式称为逗号表达式。一般表示形式为:
表达式 1 ,表达式 2 ,…,表达式 n
逗号表达式有两层含义:第一,各表达式按顺序执行;第二,逗号表达式也表达一个值,这个值是最后一个表达式的值。
例如,逗号表达式:
3*5, a+b, x=10
由3个互不相干的表达式组成,仅仅是顺序执行而已。如果有:
x = ( a = 3, 2 * 6 )
把逗号表达式a=3, 2*6的值赋给x,则x的值为12。但如果表达式写为:
x = a = 3, 5 * 6
因为逗号的运算级别最低,所以它是由两个表达式构成的逗号表达式,则x的值为3。