4. 逻辑操作符: , || , !
4. 逻辑操作符:&& , || , !
逻辑运算符提供逻辑判断功能,⽤于构建更复杂的表达式,主要有下⾯三个运算符。
注:在C语言中, 0 表示假,非零值表示真.
4.1 逻辑取反运算符 !
⽐如,我们有⼀个变量叫 flag ,如果flag为假,要做⼀个什么事情,就可以这样写代码:
int main(void) { int flag = 0; if( !flag ) { //若干语句 } return 0; }如果 flag 为真, !flag 就是假,如果 flag 为假, !flag 就是真
所以上⾯的代码的意思就是当 flag 为假时,会执⾏if语句中的代码。
int main(void) { flag = 1; // 非0 表示“真” if (!flag) printf("这行不会执行\n"); // !1 结果为 0(假),条件不成立 return 0; }反之,如上.
4.2 逻辑与运算符 &&
&& 就是与运算符,也就是"并且" "和" "and"的意思, && 是⼀个双⽬操作符,使⽤的⽅式是 a&&b , && 两边的表达式都是真的时候,整个表达式才为真,只要有⼀个是假,则整个表达式为假。
⽐如:如果我们说⽉份是3⽉到5⽉,是春天,那使⽤代码怎么体现呢?
int month = 0; scanf("%d", &month); if(month >= 3 && month <= 5) { printf("春季\n"); }这⾥的意思就是month既要⼤于等于3,⼜要⼩于等于5,必须同时满⾜。如果month满足要求,就会执行之后语句.
4.3 逻辑或运算符 ||
|| 就是或运算符,也就是或者的意思, || 也是⼀个双⽬操作符,使⽤的⽅式是 a || b , || 两边的表达式只要有⼀个是真,整个表达式就是真,两边的表达式都为假的时候,才为假.
⽐如:我们说⼀年中⽉份是12⽉或者1⽉或者2⽉是冬天,那么我们怎么使⽤代码体现呢?
int month = 0; scanf("%d", &month); if(month == 12 || month == 1 || month == 2) { printf("冬季\n"); }这里的代码就是输入的month会去匹配if中的语句,month等不等于12,不是,下一个等不等于1等等,逻辑或就是只要有一个匹配就可以判定为真,执行以后语句.
4.4 练习:闰年的判断
要求: 输入一个年份year,判断year是否是闰年.
闰年:
(1). 能被4整除并且不能被100整除的是闰年.
(2). 能被400整除是闰年
int main() { int year = 0; scanf("%d", &year); if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) printf("是闰年\n"); return 0; }这里的判断条件是使用逻辑操作符,首先整体是逻辑或操作符将两个括号里的内容相关联,其次是第一个括号中的逻辑与操作符将它左右两侧的表达式关联,即满足两个括号中任意一个的条件可以打印"是闰年".
4.5 短路
C语⾔逻辑运算符还有⼀个特点,它总是先对左侧的表达式求值,再对右边的表达式求值,这个顺序是 保证的。
如果左边的表达式满⾜逻辑运算符的条件,就不再对右边的表达式求值。这种情况称为“短路”。 如前⾯的代码:
if ( month >= 3 && month <= 5 ) //春天表达式中&&的左操作数是 结果是0的时候,即使不判断 month >= 3 ,右操作数是 month = 3 的 month <= 5 ,整个表达式的结果也是0(不是春季)。 所以,对于&&操作符来说,左边操作数的结果是0的时候,右边操作数就不再执⾏。
对于 || (逻辑或)操作符是怎么样呢?结合前面代码:
if ( month == 12 || month == 1 || month == 2 )如果month==12,则不⽤再判断month是否等于1或者2,整个表达式的结果也是1(是冬季)。 所以, || 操作符的左操作数的结果不为0时,就⽆需执⾏右操作数。
像这种仅仅根据左操作数的结果就能知道整个表达式的结果,不再对右操作数进⾏计算的运算称为短路求值
下面来两个示例来练习下逻辑操作符:
阅读代码,并计算出代码输出的结果:
示例一:
//代码1 #include <stdio.h> int main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++; printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d); return 0; }解: 在这里我们知道了四个变量的初始值和要进行的表达式,既然我们已经了解了逻辑操作符的短路原理,就可以开始计算了.
首先a的初始值为0,而a++是后置++,即先使用后加加,使用的a就是0,而逻辑与操作符必须它的操作数或表达式全为真,从前向后依次判断,只要过程中有一个假,就会中断,后续的表达式都不会再执行了.
所以这里第一个a++就被判定为假,后续表达式都不会执行,即变量a得到自增变为1,其他变量不变,竖着依次输出: 1 2 3 4
变体:如果把上述代码中的a初始化为1,结果会改变吗?有什么改变?
解: 既然a的初始值变为了0,那首先第一个会被判断为真,又 b d 都不为零,所以a b d都会自增,竖着依次输出:2 3 3 5
示例二:
int main() { int i = 0, a = 1, b = 2, c = 3, d = 4; i = a++ || ++b || d++; printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d); return 0; }解: 通过上一道题目,诸位想必都大概了解做题流程了.
首先来看第一个表达式a++,既然a被初始化为1,先使用后加加,判断为真,根据逻辑或操作符的特性,有一个表达式判断为真就不会继续执行后面的表达式了,故这里只有变量a自增了.
竖着依次输出 : 2 2 3 4
变体:若把a的值改为0,结果又会是什么呢?
a++还是先使用后加加,故第一个表达式判定为假,但这是逻辑或操作符,只要有一个表达式判定为真就可以,故接着判断下一个++b,这是前置++,先加加再使用,b初始化为2,自增后为3,判定为真,有一个为真了,就不再往后计算了.
至此,a自增为1,b自增为3,其他变量都不变,故竖着依次输出:1 3 3 4
