赞
踩
C++PrimerPlus 第六章 分支语句和逻辑运算符 - 6.2 逻辑表达式
经常需要测试多种条件。例如,字符要是小写,其值就必须大于或等于 ‘a’,且小于或等于 ‘z’。如果要求用户使用y或n进行响应,则希望用户无论输入大写(Y和N)或小写都可以。为满足这种需要,C++提供了3种逻辑运算符,来组合或修改已有的表达式。这些运算符分别是逻辑OR(||)、逻辑AND(&&)和逻辑NOT(!)。下面介绍这些运算符。
在英语中,当两个条件中有一个或全部满足某个要求时,可以用单词or来指明这种情况。例如,如果您或您在配偶在MegaMicro公司工作,您就可以参加MegaMicro公司的野餐会。C++可以采用逻辑OR运算符(||),将两个表达式组合在一起。如果原来表达式中的任何一个或全部都为true(或非零),则得到的表达式的值为true;否则,表达式的值为false。下面是一些例子:
5 == 5 || 5 == 9 //true because first expression is true
5 > 3 || 5 > 10 //true because first expression is true
5 > 8 || 5 < 10 //true because second expression is true
5 < 8 || 5 > 2 //true because both expressions are true
5 > 8 || 5 < 2 //false because both expressions are false
由于||的优先级比关系运算符低,因此不需要在这些表达式中使用括号。下表总结了||的工作原理。
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.4 or.cpp
- //or.cpp -- using the logical OR operator
- #include<iostream>
- int main()
- {
- using namespace std;
- cout << "This program may reformat your hard disk\n"
- "and destory all your data.\n"
- "Do you wish to continue?<y/n>";
- char ch;
- cin >> ch;
- if (ch == 'y' || ch == 'Y')
- cout << "You were warned!\a\a\n";
- else if (ch == 'n' || ch == 'N')
- cout << "A wise choice ... bye\n";
- else
- cout << "That wasn't a y or n! Apperantly you "
- "can't follow\ninstructions, so "
- "I'll trash your disk anyway.\a\a\a\n";
- return 0;
- }

该程序不会带来任何威胁,下面是其运行情况:
This program may reformat your hard disk
and destory all your data.
Do you wish to continue?<y/n>N
A wise choice ... bye
由于程序只读取一个字符,因此只读取响应的第一个字符。这意味着用户可以用NO!(而不是N)进行回答,程序将只读取N。然而,如果程序后面再读取输入时,将从O开始读取。
逻辑AND运算符(&&),也是将两个两个表达式组合成一个表达式。仅当原来的两个表达式都为true时,得到的表达式的值才为true。下面是一些例子:
5 == 5 && 4 == 4 //true because both expressions are true
5 == 3 && 4 == 4 //false because first expression is false
5 > 3 && 5 > 10 //false because second expression is false
5 > 8 && 5 < 10 //false because first expression is false
5 < 8 && 5 > 2 //true because both expressions are true
5 > 8 && 5 < 2 //false because both expressions are false
由于&&的优先级低于关系运算符,因此不必在这些表达式中使用括号。和||运算符一样,&&运算符也是顺序点,因此将首先判定左侧,并且在右侧被判定之前产生所有的副作用。如果左侧为false,则整个逻辑表达式必定为false,在这种情况下,C++将不会再对右侧进行判定。下表总结了&&运算符的工作方式。
程序清单6.5演示了如何用&&来处理一种常见的情况——由于两种不同的原因而结束while循环。在这个程序清单中,一个while循环将值读入到数组。一个测试(j < ArSize)在数组被填满时循环结束,另一个测试(temp >= 0)让用户通过输入一个负值来提前结束循环。该程序使用&&运算符将两个测试组合成一个条件。该程序还使用了两条if语句、一条if else语句和一个for循环,因此它演示了本章和第5章的多个主题。
程序清单6.5 and.cpp
- //and.cpp -- using the logical AND operator
- #include<iostream>
- const int ArSize = 6;
- int main()
- {
- using namespace std;
- float naaq[ArSize];
- cout << "Enter the NAAQs (New Age Awareness Quotients) "
- << "of\nyour neighbors/ Program terminates "
- << "when you make\n" << ArSize << " entries "
- << "or enter a negative value.\n";
-
- int i = 0;
- float temp;
- cout << "First value: ";
- cin >> temp;
- while (i < ArSize && temp >= 0) //2 quitting criteria
- {
- naaq[i] = temp;
- ++i;
- if (i < ArSize) //room left in the array,
- {
- cout << "Next value: ";
- cin >> temp; //so get next value
- }
- }
- if (i == 0)
- cout << "No data -- bye\n";
- else
- {
- cout << "Enter your NAAQ: ";
- float you;
- cin >> you;
- int count = 0;
- for (int j = 0; j < i; j++)
- if (naaq[j] > you)
- ++count;
- cout << count;
- cout << " of your neighbors have greater awareness of\n"
- << "the New Age than you do.\n";
- }
- return 0;
- }

注意,该程序将输入放在临时变量temp中。在核实输入有效后,程序才将这个值赋给数组。
下面是该程序的两次运行情况。一次在输入6个值后结束:
Enter the NAAQs (New Age Awareness Quotients) of
your neighbors/ Program terminates when you make
6 entries or enter a negative value.
First value: 28
Next value: 72
Next value: 15
Next value: 6
Next value: 130
Next value: 145
Enter your NAAQ: 50
3 of your neighbors have greater awareness of
the New Age than you do.
另一次在输入负值后结束:
Enter the NAAQs (New Age Awareness Quotients) of
your neighbors/ Program terminates when you make
6 entries or enter a negative value.
First value: 123
Next value: 119
Next value: 4
Next value: 89
Next value: -1
Enter your NAAQ: 123.031
0 of your neighbors have greater awareness of
the New Age than you do.
程序说明
来看看该程序的输入部分
cin >> temp; while (i < ArSize && temp >= 0) //2 quitting criteria { naaq[i] = temp; ++i; if (i < ArSize) //room left in the array, { cout << "Next value: "; cin >> temp; //so get next value } }该程序首先将第一个输入值读入到临时变量(temp)中。然后,while测试条件查看数组中是否还有空间(i < ArSize)以及输入值是否为非负(temp >= 0)。如果满足条件,则将temp的值复制到数组中,并将数组索引加1。此时,由于数组下标从0开始,因此i指示输入了多少个值。也是说,如果i从0开始,则第一轮循环将一个值赋给naaq[0],然后将i设置为1。
当数组被填满或用户输入了负值时,循环将结束。注意,仅当i小于ArSize时,即数组中还有空间时,循环才将另外一个值读入到temp中。
获得数据后,如果没有输入任何数据(即第一次输入的是一个负数),程序将使用if else语句指出这一点,如果存在数据,就对数据进行处理。
&&运算符还允许建立一系列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
- //more_and.cpp -- using the logical AND operator
- #include<iostream>
- const char* qualify[4] = //an array of pointers
- { //to strings
- "10,000-meter race,\n",
- "mud tug-of-war.\n",
- "masters canie jousting.\n",
- "pie-throwing festival.\n"
- };
- int main()
- {
- using namespace std;
- int age;
- cout << "Enter your age in years: ";
- cin >> age;
- int index;
-
- if (age > 17 && age < 35)
- index = 0;
- else if (age >= 35 && age < 50)
- index = 1;
- else if (age >= 50 && age < 65)
- index = 2;
- else
- index = 3;
-
- cout << "You qualify for the " << qualify[index];
- return 0;
- }

下面是该程序的运行情况:
Enter your age in years: 87
You qualify for the pie-throwing festival.
由于输入的年龄不与任何测试取值范围匹配,因此程序将索引设置为3,然后打印相应的字符串。
程序说明
在程序清单6.6中,表达式age > 17 && age < 35测试年龄是否位于两个值之间,即年龄是否在18岁到34岁之间。表达式age >= 35 && age < 50运算符<=运算符将35包括在取值范围内。如果程序使用age > 35 && age < 50,则35将被所有的测试忽略。在使用取值范围测试时,应确保取值范围之间既没有缝隙,又没有重叠。另外,应确保正确设置每个取值范围(参加本节后面的旁注“取值范围测试”)。
if else语句用来选择数组索引,而索引则标识特定的字符串。
取值范围测试
取值范围测试的每一部分都使用AND运算符将两个完整的关系表达式组合起来:
if (age > 17 && age < 35) //OK
不要使用数学符号将其表示为:
if (17 < age < 35) //Don’t do this!
编译器不会捕捉这种错误,因为它仍然是有效的C++语法。<运算符从左向右结合,因此上述表达式的含义如下:
if ((17 < age) < 35)
但17 < age的值要么为true(1),要么为false(0)。不管是哪种情况,表达式17 < age的值都小于35,因此整个测试的结果总是true!
!运算符将它后面的表达式的真值取反。也是说,如果expression为true,则!expression是false;如果expression为false,则!expression是true。更准确地说,如果expression为true或非零,则!expression为false。
通常,不使用这个运算符可以更清楚地表示关系:
if (!(x > 5)) //if (x <= 5) is clearer
然而,!运算符对于返回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
- //not.cpp -- using the not operator
- #include<iostream>
- #include<climits>
- bool is_int(double);
- int main()
- {
- using namespace std;
- double num;
-
- cout << "Yo, dude! Enter an integer value: ";
- cin >> num;
- while (!is_int(num)) //continue while num is not int-able
- {
- cout << "Out of range -- please try again: ";
- cin >> num;
- }
- int val = int(num); //type cast
- cout << "You've entered the integer " << val << "\nBye\n";
- return 0;
- }
- bool is_int(double x)
- {
- if (x <= INT_MAX && x >= INT_MIN) //use climits values
- return true;
- else
- return false;
- }

下面是该程序在int占32位的系统上的运行情况:
Yo, dude! Enter an integer value: 6234128679
Out of range -- please try again: -8000222333
Out of range -- please try again: 99999
You've entered the integer 99999
Bye
程序说明
如果给读取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变量。
正如本章前面指出的,C++逻辑OR和逻辑AND运算符的优先级都低于关系运算符。这意味着下面的表达式
x > 5 && x < 10
将被解释为:
(x > 5) && (x < 10)
另一方面,!运算符的优先级高于所有的关系运算符和算术运算符。因此,要对表达式求反,必须用括号将其括起,如下所示:
!(x > 5) //is it false that x is greater than 5
!x > 5 //is !x greater than 5
第二个表达式总是为false,因为!x的值只能为true或false,而它们将被转换为1或0。
逻辑AND运算符的优先级高于逻辑OR运算符。因此,表达式:
age > 30 && age < 45 || weight > 300
被解释为:
(age > 30 && age < 45) || weight > 300
也是说,一个条件是age位于31~44,另一个条件是weight大于300。如果这两个条件中的一个或全部都为true,则整个表达式为true。
当然,还可以用括号将所希望的解释告诉程序。例如,假设要用&&将age大于50或weight大于300的条件与donation大于1000的条件组合在一起,则必须使用括号将OR部分括起:
(age > 50 || weight > 300) && donation > 1000
否则,编译器将把weight条件与donation条件(而不是age条件)组合在一起。
虽然C++运算符的优先级规则常可能不使用括号便可以编写复合比较的语句,但最简单的方法还是用括号将测试进行分组,而不管是否需要括号。这样代码容易阅读,避免读者查看不常使用的优先级规则,并减少由于没有准确记住所使用的规则而出错的可能性。
C++确保程序从左向右进行计算逻辑表达式,并在知道答案后立刻停止。假如,假设有下面的条件:
x != 0 && 1.0 / x > 100.0
如果第一个条件为false,则整个表达式肯定为false。这是因为要使整个表达式为true,每个条件都必须为true。知道第一个条件为false后,程序将不判定为第二个条件。这个例子非常幸运,因为计算第二个条件将导致被0除,这是计算机没有定义的操作。
并不是所有的键盘都提供了用作逻辑运算符的符号,因此C++标准提供了另一种表示方式,如下表所示。标识符and、or和not都是C++保留字,这意味着不能将它们用作变量名等。它们不是关键字,因为它们都是已有语言特性的另一种表示方式。另外,它们并不是C语言中的保留字,但C语言程序可以将它们用作运算符,只要在程序中包含了头文件iso646.h。C++不要求使用头文件。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。