- 内容提要
- 前言
- 第 1 章 预备知识
- 第 2 章 开始学习 C++
- 第 3 章 处理数据
- 第 4 章 复合类型
- 第 5 章 循环和关系表达式
- 第 6 章 分支语句和逻辑运算符
- 第 7 章 函数——C++的编程模块
- 第 8 章 函数探幽
- 第 9 章 内存模型和名称空间
- 第 10 章 对象和类
- 第 11 章 使用类
- 第 12 章 类和动态内存分配
- 第 13 章 类继承
- 第 14 章 C++中的代码重用
- 第 15 章 友元、异常和其他
- 第 16 章 string 类和标准模板库
- 第 17 章 输入、输出和文件
- 第 18 章 探讨 C++新标准
- 附录 A 计数系统
- 附录 B C++保留字
- 附录 C ASCII 字符集
- 附录 D 运算符优先级
- 附录 E 其他运算符
- 附录 F 模板类 string
- 附录 G 标准模板库方法和函数
- 附录 H 精选读物和网上资源
- 附录 I 转换为 ISO 标准 C++
- 附录 J 复习题答案
6.2 逻辑表达式
经常需要测试多种条件。例如,字符要是小写,其值就必须大于或等于'a',且小于或等于'z'。如果要求用户使用 y 或 n 进行响应,则希望用户无论输入大写(Y 和 N)或小写都可以。为满足这种需要,C++提供了 3 种逻辑运算符,来组合或修改已有的表达式。这些运算符分别是逻辑 OR(||)、逻辑 AND(&&)和逻辑 NOT(!)。下面介绍这些运算符。
6.2.1 逻辑 OR 运算符:||
在英语中,当两个条件中有一个或全部满足某个要求时,可以用单词 or 来指明这种情况。例如,如果您或您的配偶在 MegaMicro 公司工作,您就可以参加 MegaMicro 公司的野餐会。C++可以采用逻辑 OR 运算符(||),将两个表达式组合在一起。如果原来表达式中的任何一个或全部都为 true(或非零),则得到的表达式的值为 true;否则,表达式的值为 false。下面是一些例子:
由于||的优先级比关系运算符低,因此不需要在这些表达式中使用括号。表 6.1 总结了||的工作原理。
C++规定,||运算符是个顺序点(sequence point)。也是说,先修改左侧的值,再对右侧的值进行判定(C++11 的说法是,运算符左边的子表达式先于右边的子表达式)。例如,请看下面的表达式:
i++ < 6||i== j
假设 i 原来的值为 10,则在对 i 和 j 进行比较时,i 的值将为 11。另外,如果左侧的表达式为 true,则 C++将不会去判定右侧的表达式,因为只要一个表达式为 true,则整个逻辑表达式为 true(读者可能还记得,冒号和逗号运算符也是顺序点)。
程序清单 6.4 在一条 if 语句中使用||运算符来检查某个字符的大写或小写。另外,它还使用了 C++字符串的拼接特性(参见第 4 章)将一个字符串分布在 3 行中。
表 6.1 ||运算符
expr1 ‖ expr2 的值 | ||
---|---|---|
expr1 = = true | expr1 = = false | |
expr2 = = true | true | true |
expr2 = = false | true | false |
程序清单 6.4 or.cpp
该程序不会带来任何威胁,下面是其运行情况:
由于程序只读取一个字符,因此只读取响应的第一个字符。这意味着用户可以用 NO!(而不是 N)进行回答,程序将只读取 N。然而,如果程序后面再读取输入时,将从 O 开始读取。
6.2.2 逻辑 AND 运算符:&&
逻辑 AND 运算符(&&),也是将两个表达式组合成一个表达式。仅当原来的两个表达式都为 true 时,得到的表达式的值才为 true。下面是一些例子:
由于&&的优先级低于关系运算符,因此不必在这些表达式中使用括号。和||运算符一样,&&运算符也是顺序点,因此将首先判定左侧,并且在右侧被判定之前产生所有的副作用。如果左侧为 false,则整个逻辑表达式必定为 false,在这种情况下,C++将不会再对右侧进行判定。表 6.2 总结了&&运算符的工作方式。
表 6.2 &&运算符
expr1 && expr2 的值 | ||
---|---|---|
expr1 = = true | expr1 = = false | |
expr2 = = true | true | false |
expr2 = = false | false | false |
程序清单 6.5 演示了如何用&&来处理一种常见的情况——由于两种不同的原因而结束 while 循环。在这个程序清单中,一个 while 循环将值读入到数组。一个测试(i<ArSize)在数组被填满时循环结束,另一个测试(temp>=0)让用户通过输入一个负值来提前结束循环。该程序使用&&运算符将两个测试组合成一个条件。该程序还使用了两条 if 语句、一条 if else 语句和一个 for 循环,因此它演示了本章和第 5 章的多个主题。
程序清单 6.5 and.cpp
注意,该程序将输入放在临时变量 temp 中。在核实输入有效后,程序才将这个值赋给数组。
下面是该程序的两次运行情况。一次在输入 6 个值后结束:
另一次在输入负值后结束:
程序说明
来看看该程序的输入部分:
该程序首先将第一个输入值读入到临时变量(temp)中。然后,while 测试条件查看数组中是否还有空间(i<ArSize)以及输入值是否为非负(temp >=0)。如果满足条件,则将 temp 的值复制到数组中,并将数组索引加 1。此时,由于数组下标从 0 开始,因此 i 指示输入了多少个值。也是说,如果 i 从 0 开始,则第一轮循环将一个值赋给 naaq[0],然后将 i 设置为 1。
当数组被填满或用户输入了负值时,循环将结束。注意,仅当 i 小于 ArSize 时,即数组中还有空间时,循环才将另外一个值读入到 temp 中。
获得数据后,如果没有输入任何数据(即第一次输入的是一个负数),程序将使用 if else 语句指出这一点,如果存在数据,就对数据进行处理。
6.2.3 用&&来设置取值范围
&&运算符还允许建立一系列 if else if else 语句,其中每种选择都对应于一个特定的取值范围。程序清单 6.6 演示了这种方法。另外,它还演示了一种用于处理一系列消息的技术。与 char 指针变量可以通过指向一个字符串的开始位置来标识该字符串一样,char 指针数组也可以标识一系列字符串,只要将每一个字符串的地址赋给各个数组元素即可。程序清单 6.6 使用 qualify 数组来存储 4 个字符串的地址,例如,qualify [1]存储字符串“mud tug-of-war\n”的地址。然后,程序便能够将 cout、strlen( ) 或 strcmp( ) 用于 qualify [1],就像用于其他字符串指针一样。使用 const 限定符可以避免无意间修改这些字符串。
程序清单 6.6 more_and.cpp
下面是该程序的运行情况:
由于输入的年龄不与任何测试取值范围匹配,因此程序将索引设置为 3,然后打印相应的字符串。
程序说明
在程序清单 6.6 中,表达式 age > 17 && age < 35 测试年龄是否位于两个值之间,即年龄是否在 18 岁到 34 岁之间。表达式 age >= 35 && age < 50 使用<=运算符将 35 包括在取值范围内。如果程序使用 age > 35 && age < 50,则 35 将被所有的测试忽略。在使用取值范围测试时,应确保取值范围之间既没有缝隙,又没有重叠。另外,应确保正确设置每个取值范围(参见本节后面的旁注“取值范围测试”)。
if else 语句用来选择数组索引,而索引则标识特定的字符串。
取值范围测试
取值范围测试的每一部分都使用 AND 运算符将两个完整的关系表达式组合起来:
不要使用数学符号将其表示为:
编译器不会捕获这种错误,因为它仍然是有效的 C++语法。<运算符从左向右结合,因此上述表达式的含义如下:
但 17 < age 的值要么为 true(1),要么为 false(0)。不管是哪种情况,表达式 17 < age 的值都小于 35,因此整个测试的结果总是 true!
6.2.4 逻辑 NOT 运算符:!
!运算符将它后面的表达式的真值取反。也是说,如果 expression 为 true,则!expression 是 false;如果 expression 为 false,则!expression 是 true。更准确地说,如果 expression 为 true 或非零,则!expression 为 false。
通常,不使用这个运算符可以更清楚地表示关系:
然而,!运算符对于返回 true-false 值或可以被解释为 true-false 值的函数来说很有用。例如,如果 C-风格字符串 s1 和 s2 不同,则 strcmp(s1, s2) 将返回非零(true)值,否则返回 0。这意味着如果这两个字符串相同,则!strcmp(s1, s2) 为 true。
程序清单 6.7 使用这种技术(将!运算符用于函数返回值)来筛选可赋给 int 变量的数字输入。如果用户定义的函数 is_int( )(稍后将详细介绍)的参数位于 int 类型的取值范围内,则它将返回 true。然后,程序使用 while(!is-int(num)) 测试来拒绝不在该取值范围内的值。
程序清单 6.7 not.cpp
下面是该程序在 int 占 32 位的系统上的运行情况:
程序说明
如果给读取 int 值的程序输入一个过大的值,很多 C++实现只是将这个值截短为合适的大小,并不会通知丢失了数据。程序清单 6.7 中的程序避免了这样的问题,它首先将可能的 int 值作为 double 值来读取。double 类型的精度足以存储典型的 int 值,且取值范围更大。另一种选择是,使用 long long 来存储输入的值,因为其取值范围比 int 大。
布尔函数 is_int( ) 使用了 climits 文件(第 3 章讨论过)中定义的两个符号常量(INT_MAX 和 INT_MIN)来确定其参数是否位于适当的范围内。如果是,该函数将返回 true,否则返回 false。
main( ) 程序使用 while 循环来拒绝无效输入,直到用户输入有效的值为止。可以在输入超出取值范围时显示 int 的界限,这样程序将更为友好。确认输入有效后,程序将其赋给一个 int 变量。
6.2.5 逻辑运算符细节
正如本章前面指出的,C++逻辑 OR 和逻辑 AND 运算符的优先级都低于关系运算符。这意味着下面的表达式
将被解释为:
另一方面,!运算符的优先级高于所有的关系运算符和算术运算符。因此,要对表达式求反,必须用括号将其括起,如下所示:
第二个表达式总是为 false,因为!x 的值只能为 true 或 false,而它们将被转换为 1 或 0。
逻辑 AND 运算符的优先级高于逻辑 OR 运算符。因此,表达式:
被解释为:
也是说,一个条件是 age 位于 31~44,另一个条件是 weight 大于 300。如果这两个条件中的一个或全部都为 true,则整个表达式为 true。
当然,还可以用括号将所希望的解释告诉程序。例如,假设要用&&将 age 大于 50 或 weight 大于 300 的条件与 donation 大于 1000 的条件组合在一起,则必须使用括号将 OR 部分括起:
否则,编译器将把 weight 条件与 donation 条件(而不是 age 条件)组合在一起。
虽然 C++运算符的优先级规则常可能不使用括号便可以编写复合比较的语句,但最简单的方法还是用括号将测试进行分组,而不管是否需要括号。这样代码容易阅读,避免读者查看不常使用的优先级规则,并减少由于没有准确记住所使用的规则而出错的可能性。
C++确保程序从左向右进行计算逻辑表达式,并在知道答案后立刻停止。例如,假设有下面的条件:
如果第一个条件为 false,则整个表达式肯定为 false。这是因为要使整个表达式为 true,每个条件都必须为 true。知道第一个条件为 false 后,程序将不判定第二个条件。这个例子非常幸运,因为计算第二个条件将导致被 0 除,这是计算机没有定义的操作。
6.2.6 其他表示方式
并不是所有的键盘都提供了用作逻辑运算符的符号,因此 C++标准提供了另一种表示方式,如表 6.3 所示。标识符 and、or 和 not 都是 C++保留字,这意味着不能将它们用作变量名等。它们不是关键字,因为它们都是已有语言特性的另一种表示方式。另外,它们并不是 C 语言中的保留字,但 C 语言程序可以将它们用作运算符,只要在程序中包含了头文件 iso646.h。C++不要求使用头文件。
表 6.3 逻辑运算符:另一种表示方式
运算符 | 另一种表示方式 |
---|---|
&& | and |
‖ | or |
! | not |
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论