8.3 逻辑运算符

C语言学习栏目目录

目录

1、优先级

2、求值顺序

3、范围


源码

大家应该很熟悉了if 语句和 while 语句通常使用关系表达式作为测试条件。有时,把多个关系表达式组合起来会很有用。例如,要编写一个程序,计算输入的一行句子中除单引号和双引号以外其他字符的数量。这种情况下可以使用逻辑运算符,并使用句点(.)标识句子的末尾。下程序清单用一个简短的程序进行演示。

/************************************************************************
功能: 使用逻辑与运算符                                                                     
/************************************************************************/

#include <stdio.h>
#define PERIOD '.'
int main(void)
{
	char ch;
	int charcount = 0;
	while ((ch = getchar()) != PERIOD)
	{
		if (ch != '"' && ch != '\'')
			charcount++;
	}
	printf("上面有 %d 个非引号字符.\n", charcount);
	return 0;
}

下面是该程序的一个输出示例:

你好呀.
上面有 6 个非引号字符.

程序首先读入一个字符,并检查它是否是一个句点,因为句点标志一个句子的结束。接下来,if语句的测试条件中使用了逻辑与运算符&&。该  if语句翻译成文字是“如果待测试的字符不是双引号,并且它也不是单引号,那么charcount递增1”。

逻辑运算符两侧的条件必须都为真,整个表达式才为真。逻辑运算符的优先级比关系运算符低,所以不必在子表达式两侧加圆括号。C有3种逻辑运算符,见下表

1、优先级

! 运算符的优先级很高,比乘法运算符还高,与递增运算符的优先级相同,只比圆括号的优先级低。&&运算符的优先级比||运算符高,但是两者的优先级都比关系运算符低,比赋值运算符高。

因此,表达式a >b && b > c ||b > d相当于((a > b) && (b > c)) || (b > d)。

也就是说,b介于a和c之间,或者b大于d。

尽管对于该例没必要使用圆括号,但是许多程序员更喜欢使用带圆括号的第 2 种写法。这样做即使不记得逻辑运算符的优先级,表达式的含义也很清楚

2、求值顺序

除了两个运算符共享一个运算对象的情况外,C 通常不保证先对复杂表达式中哪部分求值。例如,下面的语句,可能先对表达式5 + 3求值,也可能先对表达式9 + 6求值:

apples = (5 + 3) * (9 + 6);

C 把先计算哪部分的决定权留给编译器的设计者,以便针对特定系统优化设计。但是,对于逻辑运算符是个例外,C保证逻辑表达式的求值顺序是从左往右。&&和||运算符都是序列点,所以程序在从一个运算对象执行到下一个运算对象之前,所有的副作用都会生效。而且,C 保证一旦发现某个元素让整个表达式无效,便立即停止求值。正是由于有这些规定,才能写出这样结构的代码:
 

while ((c = getchar()) != ' ' && c != '\n')

如上代码所示,读取字符直至遇到第1 个空格或换行符。第1 个子表达式把读取的值赋给c,后面的子表达式会用到c的值。如果没有求值循序的保证,编译器可能在给c赋值之前先对后面的表达式求值。这里还有一个例子

if (number != 0 && 12/number == 2)
    printf("The number is 5 or 6.\n");

如果number的值是0,那么第1个子表达式为假,且不再对关系表达式求值。这样避免了把0作为除数。许多语言都没有这种特性,知道number为0后,仍继续检查后面的条件。最后,考虑这个例子:

while ( x++ < 10 && x + y < 20)

实际上,&&是一个序列点,这保证了在对&&右侧的表达式求值之前,已经递增了x。

小结:逻辑运算符和表达式

逻辑运算符:

逻辑运算符的运算对象通常是关系表达式。!运算符只需要一个运算对象,其他两个逻辑运算符都需要两个运算对象,左侧一个,右侧一个。

逻辑表达式:

当且仅当expression1和expression2都为真,expression1 && expression2才为真。如果 expression1 或 expression2 为真,expression1 || expression2 为真。如果expression为假,!expression则为真,反之亦然。

求值顺序:

逻辑表达式的求值顺序是从左往右。一旦发现有使整个表达式为假的因素,立即停止求值。

示例:

6 > 2 && 3 == 3    真
!(6 > 2 && 3 == 3)   假

x != 0 && (20 / x) < 5 只有当x不等于0时,才会对第2个表达式求值

3、范围

&&运算符可用于测试范围。例如,要测试score是否在90~100的范围内,可以这样写:

if ((range >= 90 )&& (range <= 100))
    printf("Good show!\n");

千万不要模仿数学上的写法: 

if (90 <= range <= 100)  // 千万不要这样写!
    printf("Good show!\n");

这样写的问题是代码有语义错误,而不是语法错误,所以编译器不会捕获这样的问题(虽然可能会给出警告)。由于<=运算符的求值顺序是从左往右,所以编译器把测试表达式解释为:

(90 <= range) <= 100

子表达式90 <= range的值要么是1(为真),要么是0(为假)。这两个值都小于100,所以不管range的值是多少,整个表达式都恒为真。因此,在范围测试中要使用&&。

许多代码都用范围测试来确定一个字符是否是小写字母。例如,假设ch是char类型的变量:

if (ch >= 'a' && ch <= 'z')
    printf("That's a lowercase character.\n");

该方法仅对于像ASCII这样的字符编码有效,这些编码中相邻字母与相邻数字一一对应。但是,对于像EBCDIC这样的代码就没用了。

©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页