条件语句 if & switch

罗大富 BigRich大约 12 分钟C/C++

在 C 语言中,条件语句 是用于根据特定条件决定程序执行路径的关键结构,它们通过判断条件的真假来选择执行不同的代码块。我们主要用到的条件语句包括 if 语句、else 语句、else if 语句和 switch 语句。

在你的日常生活中,肯定发现过这样的现象,有的工作就是一个动作序列从头到尾执行完就行了,比如每天上班打卡;有些工作需要根据不同的情况进行不同的处理,比如垃圾分类;有的工作则是简单机械地重复,比如你刷抖音。

流程控制

计算机程序在解决某个具体的问题时,也包括以上三种情形:

  1. 顺序执行所有的语句:从上往下执行,是程序默认的执行方式,例如:

    int a = 7, b = 3;
    printf("a + b = %d\n", a + b);
    printf("a - b = %d\n", a - b);
    printf("a * b = %d\n", a * b);
    printf("a / b = %.2f\n", (float)a / b);
    
  2. 选择执行部分语句:根据条件选择是否执行

  3. 循环执行部分语句:重复执行某些语句

正好对应着 C 语言程序设计中的三种程序执行结构流程:

  1. 顺序结构;
  2. 分支结构;
  3. 循环结构。

事实证明,任何一个能用计算机解决的问题,都可以通过这三种基本结构写出的程序解决。

布尔表达式

分支结构对应的是 C 语言中的条件语句;循环结构对应的则是 C 语言中的循环语句。那什么是条件语句和循环语句呢?我们将通过两个章节来为大家讲解。

无论是学习条件语句还是循环语句,我们都需要用到 布尔表达式(结果为 true 或 false),学习布尔表达式就需要先了解布尔数据类型。

布尔(Boolean)是编程和逻辑学中的基本概念,主要用于表示逻辑为真(True) 和逻辑为假(False)。

C99 标准引入了内置的布尔类型 _Bool,它是 C 语言中最小的整数类型。

_Bool 只能存储两种值:

  • 0(假);
  • 1(真)。

在赋值时 _Bool 会自动将任何非 0 值转换为 1,这增强了类型安全性,例如:

#include <stdio.h>


int main() {
    _Bool a = 0;    // 假
    _Bool b = 100;  // 非 0,自动转为 1(真)
    // 输出时用 %d,因为它是整数类型
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    return 0;
}

输出结果为:

a = 0
b = 1

为了让布尔类型更符合现代编程习惯,C99 提供了头文件 stdbool.h,它定义了以下宏:

  • bool:等价于 _Bool,更简洁。
  • true:值为 1,表示真。
  • false:值为 0,表示假。
按住 Ctrl 鼠标左键点击引入的 stdbool.h 即可打开该文件
按住 Ctrl 鼠标左键点击引入的 stdbool.h 即可打开该文件
#include <stdio.h>
#include <stdbool.h>


int main() {
    bool a = true;
    bool b = false;
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    return 0;
}

运行结果:

a = 1
b = 0

_Bool 提供了原生的布尔支持,但名字带有下划线,不够直观,因此实际开发中通常结合 <stdbool.h> 使用。

了解了布尔之后,我们就可以来学习布尔表达式了,布尔表达式是编程中用于进行逻辑判断的表达式。其结果为真(True)或假(False)。在 C 语言中,布尔表达式通常由:

  • 比较运算
  • 逻辑运算

二者组合而成,用于控制程序的分支和循环逻辑。

比较运算就需要用到比较运算符,下表是比较运算符:

比较运算符含义示例说明
<小于a < b判断 a 是否小于 b,小于则逻辑为真
<=小于等于a <= b判断 a 是否小于等于 b,小于等于则逻辑为真
>大于a > b判断 a 是否大于 b,大于则逻辑为真
>=大于等于a >= b判断 a 是否大于等于 b,大于等于则为真
==等于a == b严格判断 a 和 b 是否相等,等于则逻辑为真
!=不等于a!=b判断 a 和 b 是否不相等,不等于则逻辑为真

注意避免混淆赋值与比较:

x = 5  // 将 5 赋值给 x
x == 5 // 布尔表达式,判断 x 与 5 是否相等

了解了比较运算符之后,我们可以看看下面几道练习题:

已知 a = 5, b = 10,判断下列布尔表达式的结果:

a == 5
a > b
b != 10
a+5 < b
b % 2 == 0

其中 % 表示取余操作 b % 2 == 0 表示 b 对 2 取余,余数再与 0 进行相等比较,因此,

我们可以把上面的题目转换成下面的代码,打印在 Clion 的控制台中:

#include <stdio.h>


int main() {
    int a = 5, b = 10;

    printf("a == 5 的逻辑值为:%d\n", a == 5);
    printf("a > b 的逻辑值为:%d\n", a > b);
    printf("b != 10 的逻辑值为:%d\n", b != 10);
    printf("a + 5 < b 的逻辑值为:%d\n", a + 5 >= b);
    printf("b % 2 == 0 的逻辑值为:%d\n", b % 2 == 0);
}

逻辑运算就需要用到对应的逻辑运算符,下表是 C 语言中常见的逻辑运算符:

比较运算符含义示例说明
&&逻辑与 anda && b在判断过程中,只要出现了假就不继续判断了。1 假则假,全真才真
||逻辑或 ora||b在判断过程中,只要出现了真就不继续判断了。1 真则真,全假才假
!逻辑非 not!a反转布尔值

下表为逻辑运算的真值表:

ab!a!ba&&ba || b
1(True)1(True)0(False)0(False)1(True)1(True)
100101
011001
001100

在 C 语言中,运算量:0 为假,非 0 为真。

了解了逻辑运算符之后,我们可以看看下面几道练习题:

已知 a = 1, b = 0,判断下列布尔表达式的结果:

a && b
a || b
!(a || b)
!a || b
a || !b
a && !b

我们可以把上面的题目转换成下面的代码,打印在 Clion 的控制台中:

#include <stdio.h>


int main() {
    int a = 1, b = 0;
    printf("a && b 的结果为:%d\n", a && b);
    printf("a || b 的结果为:%d\n", a || b);
    printf("!(a || b) 的结果为:%d\n", !(a || b));
    printf("!a || b 的结果为:%d\n", !a || b);
    printf("a || !b 的结果为:%d\n", a || !b);
    printf("a && !b 的结果为:%d\n", a && !b);
}

布尔表达式在实际应用的时候通常都会将不同的运算符混合起来使用,比如:

  1. 登录验证:若用户名为 "admin" 且密码为 "123456",则登录成功:

    username == "admin" && password == "123456"
    
  2. 温度报警器:当温度低于 -10°C 或者 40°C 时,为危险温度:

    temp < -10 || temp > 40
    

但是,需要注意的是不同的运算符的优先级是不同的,运算符遵循下面的排序

括号运算符 > ! > 算术运算符(加、减、乘、除、取余)> 比较运算符(>、<、==) > 逻辑运算符 && > 逻辑运算符 ||

尽管 !、&&、|| 同为逻辑运算符,但是 ! 的优先级远高于 &&,&& 高于 ||。

if 条件语句

在上节课中我们将变量比喻为收纳盒,每个盒子可以存放特定类型的数据(如整数、字符等),但仅有收纳盒还不够,例如我们在整理房间时,需要根据物品属性选择放入哪个收纳盒中,条件语句 便是这个分类决策的工具。

我们可以再举一个最简单的例子:

判断一个数是奇数还是偶数

像这样的判断操作,我们就需要使用 if 语句

if 语句的结构如下:

if (条件) {
    // 条件为真时执行的代码块
}

其中的 条件:必须是一个布尔表达式(结果为 true 或 false)。

而由大括号 {} 包括的代码块,可以写任意合法的语句。

这样,我们前面的代码就可以这么写:

#include <stdio.h>


int main() {
   int number = 10;
   // 判断 number 是否能被 2 整除
   if (number % 2 == 0) {
       printf("%d 是偶数", number);
   }
   return 0;
}

else 语句

上面这道程序实际上还是存在一定的瑕疵,因为我们的题目是判断是奇数还是偶数,但是,上面的代码只能判断一个数是不是偶数,如果我们传递的数字为奇数,该程序就没有结果输出。

因此,我们还需要让程序处理 number 不能被 2 整除的情况,也就是 条件不满足 时需要执行的代码。

这时候,我们就需要添加 else 分支来处理条件为假时执行的操作:

if (条件) {
    // 条件为真时执行的代码
} else {
    // 条件为假时执行的代码
}

因此,判断奇数还是偶数的代码可以这么写:

#include <stdio.h>


int main() {
    int number = 7;
    // 判断 number 是否能被 2 整除
    if (number % 2 == 0) {
        printf("%d 是偶数", number);
    } else {
        printf("%d 是奇数", number);
    }
    return 0;
}

else if 语句

我们已经学习了如何判断一个条件,但是,世界不是非黑即白的,无论是在日常生活中,还是实际开发的过程中,我们还需要经常判断多个条件的情况,举个例子:

判断一个数字是正数、负数还是 0。

这个时候,我们就没有办法只使用 if 和 else 完成判断了,因为我们需要判断多个条件,先判断该数字是不是大于 0,再判断该数字是不是小于 0,如果该数字既不大于 0,也不小于 0,那就说明这个数字是 0。

那么此时我们就可以使用 else if 来满足在多个条件中选择一个执行。其结构如下:

if (条件1) {
    // 条件 1 为真时执行的代码
} else if (条件2) {          // 当条件 1 不满足时,再判断条件 2
    // 条件 2 为真时执行的代码
} else {                          
    // 当条件 1 和条件2 都不满足的时候,进入 else 代码块  
}

那么现在,我们就可以把判断正负数与 0 的程序写出来,代码如下:

#include <stdio.h>


int main() {
    int number = 0;

    if (number > 0) {
        printf("%d 为正数", number);
    } else if (number < 0) {
        printf("%d 为负数", number);
    } else {
        printf("0");
    }

    return 0;
}

在同一个 if 代码块中,if 和 else 只能有 1 个,但是 else if 可以有无数个,我们可以再来看一个示例:

根据学生成绩,判断并输出成绩的等级:

成绩 >= 90 为优;
成绩 80-89 为良;
成绩 70-79 为中;
成绩 < 70 为差。

在这里,我们需要判断 3 次,先判断成绩是否 >= 90,再判断成绩是否 >= 80,再判断成绩是否 >= 70,如果全部不符合,则说明成绩 < 70,代码如下:

#include <stdio.h>


int main() {
    int score = 85;                 // 声明我们的分数为 85 分
    if (score >= 90) {              // 条件1:>= 90 则为优
        printf("优");
    }
    // 条件 2:判断成绩是否 >= 80,
    // 注意:此时的判断说明条件 1 已经为假,也就是说 score < 90 是确定的
    else if (score >= 80) {
        printf("良");
    }
    // 判断是否 >= 70,注意:此时的判断说明条件 1、2 已为假,也就是说 score < 80是确定的
    else if (score >= 70){
        printf("中");
    }
    // 此时的判断 score < 70 是确定的
    else {
        printf("差");
    }
}

if 语句的嵌套

如前所述,{} 中可以放置任意合法的语句,意思就是说,我们可以在 if 语句的 {} 内,再写新的 if 语句,像这种一层包裹一层的结构,我们称之为 if 语句的嵌套,结构如下:

// 这是一个双层嵌套的 if 语句
if (外部条件) {
   // 外部 if 对应的代码块
   
   if (内部条件) {
      // 内部 if 对应的代码块
   } else {
      // 内部 else 对应的代码块
   }
   
   // 外部 if 对应的代码块
   
} else {
   // 外部 else 对应的代码块
   
   // 在 else 中也可以使用同样的 if 嵌套
   if (else 内部的条件) {
      // 内部 if 对应的代码块
   }
}

这是一个 if 语句嵌套的练习题:

求三个数的最大值(要求使用嵌套 if)

代码如下:

#include <stdio.h>


int main(){
    
    int a, b, c, max;
    a = 2;
    b = 8;
    c = 5;
    // 嵌套 if 比较逻辑
    if (a > b) {
        if (a > c) {
            max = a;    // a > b且a > c,则a最大
        } else {
            max = c;    // a > b但a ≤ c,则c最大
        }
    } else {
        if (b > c) {
            max = b;    // a ≤ b且b > c,则b最大
        } else {
            max = c;    // a ≤ b且b ≤ c,则c最大
        }
    }

    printf("最大值为:%d\n", max);
    return 0;
}

练习 2:

给定三角形的三边长 a, b, c,判断:

1. 是否能构成三角形(任意两边之和大于第三边)
2. 如果能构成三角形,进一步判断是等边、等腰还是普通三角形。

代码如下:

#include <stdio.h>

int main() {
    // 定义三角形三条边的变量并赋值
    int a = 3, b = 4, c = 5;

    // 先判断是否能够构成三角形
    if (a + b > c && a + c > b && b + c > a) {
        // 再判断能否构成等边三角形
        if (a == b && b == c) {
            printf("可以构成等边三角形\n");
        }
        // 最后判断能否构成等腰三角形
        else if (a == b || a == c || b == c) {
            printf("可以构成等腰三角形\n");
        }
        else {
            printf("可以构成普通三角形\n");
        }
    }
    else {
        printf("无法构成三角形\n");
    }
    return 0;
}

switch 语句

switch 语句是 C 语言中的一种多分支选择结构,用于根据某个变量的值选择执行不同的代码块。它使得程序在处理多个条件时,比一系列的 if-else 语句更加简洁和高效。

基本语法如下:

switch (表达式) {
    case 常量1:
        // 执行语句 1;
        break;
    case 常量2:
        // 执行语句 2;
        break;
    case 常量3:
        // 执行语句 3;
        break;
    // ...
    default:
        // 执行默认语句;
}
  • expression:条件表达式,通常是一个变量或常量。switch 会根据 expression 的值去匹配相应的 case。
  • case 常量:每个 case 后面跟着一个常量值,如果 expression 的值与某个常量值匹配,则执行该 case 下的代码块。
  • break:跳出 switch 语句。如果不写 break,程序会继续执行下一个 case 语句,直到遇到 break 或 switch 语句结束。
  • default:可选项,当所有 case 都不匹配时,执行 default 后的语句。default 语句通常放在 switch 的最后。

示例如下:

#include <stdio.h>


int main() {
    int day;
    printf("输入 1~7 中的一个整数:");
    scanf("%d", &day);

    switch (day) {
        case 1:
            printf("星期一\n");
            break;

        case 2:
            printf("星期二\n");
            break;

        case 3:
            printf("星期三\n");
            break;

        case 4:
            printf("星期四\n");
            break;

        case 5:
            printf("星期五\n");
            break;

        case 6:
            printf("星期六\n");
            break;

        case 7:
            printf("星期天\n");
            break;

        default:
            printf("输入日期无效\n");
    }

    return 0;
}

上次编辑于:
贡献者: 罗大富BigRich