《小菜狗 C 语言入门 + 进阶笔记》(17)复杂判断语句和 运算符【判断语句运算符的最全讲解】


《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介


在之前的 (2.15)运算符 文章中讲过各种各样的运算符。

运算符通用于 选择结构循环结构,使代码更加简洁,更符合现实。

其中最常用的运算符就是关系运算符逻辑运算符,以及三目条件运算符。

怎么区分几目运算符?

在 C 语言中,有的运算符有两个操作数,例如 10+20,10 和 20 都是操作数,+ 是运算符。我们将这样的运算符称为双目运算符。同理,将有一个操作数的运算符称为单目运算符,将有三个操作数的运算符称为三目运算符。

常见的双目运算符+、-、*、/ 等单目运算符++、-- 等,三目运算符只有一个,就是 ? : x ? y : z -- 如果条件为真 ? 则值为 X : 否则值为 Y

1、关系运算符

1.1、定义

用于比较的表达式,称为关系表达式

运算符描述实例
==检查两个操作数的值是否相等,如果相等则条件为真。(A == B) 为假。
!=检查两个操作数的值是否相等,如果不相等则条件为真。(A != B) 为真。
>检查左操作数的值是否大于右操作数的值,如果是则条件为真。(A > B) 为假。
<检查左操作数的值是否小于右操作数的值,如果是则条件为真。(A < B) 为真。
>=检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。(A >= B) 为假。
<=检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。(A <= B) 为真。
1.2、作用

关系运算符在使用时,它的两边都会有一个表达式,比如变量、数值、加减乘除运算或表达式等。

例如:

  1. a+b > c-d
  2. x > 3/2
  3. ‘a’+1 < c
  4. -i-5*j == k+1

关系运算符也可以嵌套使用

例如:

  1. a > (b > c)
  2. a != (c == d)

关系运算符的作用就是判明这两个表达式的大小关系

**注意:**是判明大小关系,不是其他关系。

1.3、优先级

关系运算符都是双目运算符,其结合性均为左结合。关系运算符的优先级低于算术运算符,高于赋值运算符。

在六个关系运算符中,<、<=、>、>= 的优先级相同,高于 == 和 !=,其中 == 和 != 的优先级相同。

1.4、运算结果

关系运算符的运算结果只有 0 或 1。当条件成立时结果为 1,条件不成立结果为 0。

例如:

  • 5>0 成立,其值为 1;
  • 34-12>100 不成立,其值为 0;
  • (a=3)>(b=5) 由于 3>5 不成立,故其值为 0。

我们将运算结果 1 称为“真”,表示条件成立,将 0 称为“假”,表示条件不成立。

1.5、举例

下面的代码会将关系运算符的结果输出:

#include <stdio.h>
int main(){
    char c='k';
    int i=1, j=2, k=3;
    float x=3e+5, y=0.85;
    int result_1 = 'a'+5<c, result_2 = x-5.25<=x+y;
    printf( "%d, %d\n", result_1, -i-2*j>=k+1 );
    printf( "%d, %d\n", 1<j<5, result_2 );
    printf( "%d, %d\n", i+j+k==-2*j, k==j==i+5 );
    return 0;
}

运行结果:

1, 0
1, 1
0, 0

解释说明: 对于含多个关系运算符的表达式,如 kji+5,根据运算符的左结合性,先计算 kj,该式不成立,其值为 0,再计算 0i+5,也不成立,故表达式值为 0。

1.6、if 语句的判断条件

if 语句的判断条件中不是必须要包含关系运算符,它可以是赋值表达式,甚至也可以是一个变量。

如程序段:

if (a=b)
    printf("%d",a);
else
    printf("a=0");

意思是,把 b 的值赋予 a,如果为非 0 则输出该值,否则输出“a=0”字符串。这种用法在后面的程序中会经常出现。

1.7、进阶使用

注意 1:

相等运算符 ==赋值运算符 = 是两个不⼀样的运算符,==才表示等于,而=表示赋值,不要混淆。

有的程序员喜欢将变量写在等号的右边,如下:

if (3 == x) ...

这样的话,如果把 == 误写成 = ,编译器就会报错。

/* 报错 */
if (3 = x) ...

注意 2:

多个关系运算符不宜连用。如下:

i < j < k

上面示例中,连续使用两个小于运算符。这是合法表达式,不会报错,但是通常达不到想要的结果,即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执行的是下面的表达式。

(i < j) < k 

上面式子中, i < j 返回 0 或 1 ,所以最终是 0 或 1 与变量 k 进行比较。如果想要判断变量 j 的值是否在 i 和 k 之间,应该使用下面的写法:

i < j && j < k 

比如:我们输入⼀个年龄,如果年龄在 18 岁 ~ 36 岁之间,我们输出青年。

如果我们这样写:

#include <stdio.h>
int main()
{
    int age = 0;
    scanf("%d", &age);
    if (18<=age<=36)
    {
        printf("青年\n");
    }
    return 0;
}

当我们输入 10 的时候,依然输出 青年!

这是因为,我们先拿 18 和 age 中存放的 10 比较,表达式 18<=10 为假, 18<=age 的结果是 0,再拿 0 和 36 比较,0<=36 为真,所以打印了 青年 ,所以即使当 age 是 10 的时候,也能打印 青年 ,逻辑上是有问题,这个代码应该怎么写呢?如下就是规范代码:

#include <stdio.h>
int main()
{
    int age = 0;
    scanf("%d", &age);
    if (age>=18 && age<=36)
    {
        printf("青年\n");
    }
    return 0;
}

2、逻辑操作符

2.1、引入

假设有这样一种情况:我们的软件比较特殊,要求使用者必须成年,并且考试成绩大于等于 60,该怎么写代码呢?

首先我们使用嵌套的 if 语句,类似下面这样的代码:

#include <stdio.h>
int main()
{
    int age;
    float score;
    printf("请输入你的年龄和成绩:");
    scanf("%d %f", &age, &score);
    if (age >= 18) {
        if (score >= 60) {
            printf("你满足条件,欢迎使用该软件\n");
        } else{
            printf("抱歉,你的成绩不及格,不能使用该软件\n");
        }
    } else {
        printf("抱歉,你还未成年,不能使用该软件!\n");
    }
    return 0;
}

但是在我看来上面代码不够简洁,我们可以将其压缩为一条 if else 语句

#include <stdio.h>
int main()
{
    int age;
    float score;
    printf("请输入你的年龄和成绩:");
    scanf("%d %f", &age, &score);
    if(age>=18 && score>=60){
        printf("你满足条件,欢迎使用该软件\n");
    }else{
        printf("抱歉,你还未成年,或者成绩不及格,不能使用该软件!\n");
    }
    return 0;
}

&&为逻辑运算符 – ,表示 age>=18score>=60 两个条件必须同时成立才能执行 if 后面的代码,否则就执行 else 后面的代码。

2.2、定义

逻辑运算符提供逻辑判断功能,用于构建更复杂的表达式,主要有下面三个运算符。

运算符描述实例
&&称为逻辑与运算符。如果两个操作数都非零,则条件为真。(A && B) 为假。
||称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。(A || B) 为真。
!称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。!(A && B) 为真。
2.2.1、逻辑与运算符

在这里插入图片描述

&& 就是与运算符,也是并且的意思, && 是⼀个双⽬操作符,使用的⽅式是 a&&b ,&& 两边的表达式都是真的时候,整个表达式才为真,只要有⼀个是假,则整个表达式为假。

如果我们说月份是 3 月 ~ 5 月,是春天。

代码如下:

int month = 0;
scanf("%d", &month);
if (month >= 3 && month <= 5)
{
    printf("春季\n");
}

解释:

month 既要大于等于 3,⼜要小于等于 5,必须同时满足。

2.2.2、逻辑或运算符

在这里插入图片描述

|| 就是或运算符,也就是或者的意思,|| 也是⼀个双⽬操作符,使用的⽅式是 a || b,|| 两边的表达式只要有⼀个是真,整个表达式就是真,两边的表达式都为假的时候,才为假。

如果我们说月份是 3 月 ~ 5 月,是春天。

代码如下:

int month = 0;
scanf("%d", &month);
if (month == 12 || month==1 || month == 2)
{
    printf("冬季\n");
}

解释:

month 从左往右判断,只要有一个条件满足就打印。

2.2.3、逻辑取反运算符在这里插入图片描述

参与运算的表达式为真时,结果为假;参与运算的表达式为假时,结果为真。例如:

!0

解释:

0 为假,非运算的结果为真,也就是 1。

!(5>0)

解释:

5>0 的结果是 1,为真,非运算的结果为假,也就是 0。

2.3、综合举例
#include <stdio.h>
int main(){
    int a = 0, b = 10, c = -6;
    int result_1 = a&&b, result_2 = c||0;
    printf("%d, %d\n", result_1, !c);
    printf("%d, %d\n", 9&&0, result_2);
    printf("%d, %d\n", b||100, 0&&0);
    return 0;
}

运行结果:

0, 0
0, 1
1, 0
2.4、优先级

逻辑运算符和其它运算符优先级从低到高依次为:

赋值运算符(=) < && 和 || < 关系运算符 < 算术运算符 < 非(!)

&& 和 || 低于关系运算符,! 高于算术运算符。

按照运算符的优先顺序可以得出:

  • a>b && c>d 等价于 (a>b)&&(c>d)
  • !b==c||d<a 等价于 ((!b)==c)||(d<a)
  • a+b>c&&x+y<b 等价于 ((a+b)>c)&&((x+y)<b)

另外,逻辑表达式也可以嵌套使用,例如 a>b && b || 9>ca || c>d && !p

逻辑运算符优先级举例:

#include <stdio.h>
int main(){
    char c='k';
    int i=1,j=2,k=3;
    float x=3e+5,y=0.85;
    printf( "%d,%d\n", !x*!y, !!!x );
    printf( "%d,%d\n", x||i&&j-3, i<j&&x<y );
    printf( "%d,%d\n", i==5&&c&&(j=8), x+y||i+j+k );
    return 0;
}

运行结果:

0,0
1,0
0,1

详细分析:

  • !x 和 !y 分别为 0,!x*!y 也为 0,故其输出值为 0。
  • 由于 x 为非 0,故 !!!x 的逻辑值为 0。
  • 对 x|| i && j-3 式,先计算 j-3 的值为非 0,再求 i && j-3 的逻辑值为 1,故 x||i&&j-3 的逻辑值为 1。
  • 对 i<j&&x<y 式,由于 i<j 的值为 1,而 x<y 为 0 故表达式的值为 1,0 相与,最后为 0。
  • 对 i5&&c&&(j=8) 式,由于 i5 为假,即值为 0,该表达式由两个与运算组成,所以整个表达式的值为 0。
  • 对于式 x+ y||i+j+k,由于 x+y 的值为非 0,故整个或表达式的值为 1。
2.5、进阶理解

逻辑运算符它总是先对左侧的表达式求值,再对右边的表达式求值。如果左边的表达式满足逻辑运算符的条件,就不再对右边的表达式求值。

如前面的代码:

if (month >= 3 && month <= 5) 

表达式中 && 的左操作数是 month >= 3 ,右操作数是 month <= 5 ,当左操作数 month >= 3 的结果是 0 的时候,即使不判断 month <= 5 ,整个表达式的结果也是 0(不是春季)。

所以,对于 && 操作符来说,左边操作数的结果是 0 的时候,右边操作数就不再执行。

对于 || 操作符是怎么样呢?我们结合前面的代码:

if (month == 12 || month==1 || month == 2) 

如果 month==12,则不用再判断 month 是否等于 1 或者 2,整个表达式的结果也是 1(是冬季)。所以, || 操作符的左操作数的结果不为 0 时,就⽆需执行右操作数。

3、条件操作符

3.1、引入

如果希望获得两个数中最大的一个,可以使用 if else 语句,例如:

if (a>b) {
    max = a;
} else {
    max = b;
}

该语句的语义是:

如 a>b 为真,则把 a 赋予 max,否则把 b 赋予 max。

不过,C 语言提供了一种更加简单的方法,叫做条件运算符。条件表达式通常用于赋值语句之中。

3.2、语法
表达式 1 ? 表达式 2 : 表达式 3

条件操作符的计算逻辑是:

  • 如果 表达式 1 为真, 下一条语句是表达式 2
  • 如果 表达式 1 为假, 下一条语句是表达式 3

因此上面的 if else 语句等价于:

max = (a>b) ? a : b;
3.3、进阶使用
  • 条件运算符 ?一对运算符,不能分开单独使用。
  • 条件运算符的优先级低于关系运算符和算术运算符,但高于赋值符。
max=(a>b) ? a : b;

可以去掉括号写成

max=a>b ? a : b;
  • 条件运算符的结合方向是自右至左。例如:
a>b ? a : c>d ? c : d;

应理解为:

a>b ? a : ( c>d ? c : d );

这也就是条件表达式嵌套的情形,即其中的表达式又是一个条件表达式。

4、容易出错的 if 语句

if 语句,虽然看上去很简单,但是在实际写代码的时候,也是很容易出错的,这⾥就总结 5 种情况。

4.1、在 if 语句的后边加上了分号
#include <stdio.h>
int main()
{
    int n = 0;
    scanf("%d", &n);
    if (n>0);
        printf("hehe\n");
    return 0;
}

上述的代码,不管 n 是大于 0 还是小于 0,最终都会输出 hehe,因为 if 语句的后边加了⼀个分号,⼀个分号就是⼀个空语句,那么如果 n>0 则执行⼀条空语句。

4.2、判断相等时使用了 =

在 C 语⾔中, = 是赋值, == 是判断相等,这两个操作符⾮常容易混用。

#include <stdio.h>
int main()
{
    int n = 0;
    if (n = 1) //这⾥不是判断,⽽是赋值,赋值后表达式的结果是1,所以打印 hehe
        printf("hehe\n");
    if (n == 1) //这⾥是判断,n不等于1,所以不打印 haha
        printf("haha\n");
    return 0;
}
4.3、判断 3 个变量相等时使用了 ==
#include <stdio.h>
int main()
{
    int a = 2;
    int b = 2;
    int c = 2;
    //错误写法
    if(a == b == c)
        printf("a,b,c相等\n");
    else
        printf("不相等\n");
    //正确的写法
    if(a==b && b==c)··
        printf("a,b,c相等\n");
    else
        printf("不相等\n");
    return 0;
}
4.4、两个条件的判断条件时没使用 && 或 ||
#include <stdio.h>
int main()
{
    int a = 2;
    //错误的写法
    if(3<=a<=5)
        printf("Yes\n");
    else
        printf("No\n");
    //正确的写法
    if(a>=3 && a<=5)
        printf("Yes\n");
    else
        printf("No\n");
    return 0;
}
4.5、使用位运算代替了逻辑运算符
int a = 1;
if (3<=a & a<= 5) //这种是错误的写法, 操作符 & 是按照对应⼆进制位做与运算的
if (a>=3 && a<=5) //正确的写法

注意 | 和 || 的区别, | 是⼆进制位的或运算, || 是逻辑或运算的。

《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介


每日一更!

公众号、优快云等博客:小菜狗编程笔记

谢谢点赞关注哈!目前在飞书持续优化更新~

日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小菜狗编程笔记

你的鼓励将是我最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值