← 课程目录
第 6 讲 模块二:让程序做判断

多分支与逻辑运算符

6 / 24
💡
本节课目标
else if 把判断从两条路扩展到多条路,理解它“一旦命中就跳过其余”的执行规则; 再用 &&||! 把多个条件组合成一个, 写出“区间判断”这类更复杂的逻辑。
开场

两条路不够用

📖 理论讲解

多条路的场景

上节课的 if / else 只能选两条路。但现实里常有三条、四条甚至更多: 成绩分 A / B / C / D / E 五档,年龄分婴儿 / 儿童 / 少年 / 成年 / 老年。

上节课练习里“两个数相等”的第三种情况,本质也是同样的问题—— if / else 给不出第三条路。今天就来解决它。

第一段

else if:串起多条路

📖 理论讲解

语法:在 if 和 else 之间插入更多判断

ifelse 之间插入 else if (条件), 就能多出一条路。可以连续写很多个 else if

Python

Python:elif 是一个独立关键字

if age < 1:

elif age < 12:

else:

VS
C++

C++:elseif 是两个词

if (age < 1) {

} else if (age < 12) {

} else {

age_classifier.cpp CPP
#include <iostream>

int main() {
    int age;
    std::cout << "请输入年龄:";
    std::cin >> age;

    if (age < 1) {
        std::cout << "婴儿" << std::endl;
    } else if (age < 12) {
        std::cout << "儿童" << std::endl;
    } else if (age < 18) {
        std::cout << "少年" << std::endl;
    } else if (age < 60) {
        std::cout << "成年" << std::endl;
    } else {
        std::cout << "老年" << std::endl;
    }
    return 0;
}
执行规则:命中就停
从上到下逐个判断,第一个成立的分支执行后,其余全部跳过—— 哪怕后面的条件也成立。这条规则是今天最重要的一句话。
⚡ 动手实操 约 15 分钟

猜输出:这两种写法错在哪

下面两段代码都是上面年龄分类器的“变体”。分别代入 age = 51270,猜一猜各自会输出什么:

wrong_order.cpp CPP
if (age < 60) {
    std::cout << "成年" << std::endl;
} else if (age < 18) {
    std::cout << "少年" << std::endl;
} else if (age < 12) {
    std::cout << "儿童" << std::endl;
} else if (age < 1) {
    std::cout << "婴儿" << std::endl;
} else {
    std::cout << "老年" << std::endl;
}
no_else.cpp CPP
if (age < 1) {
    std::cout << "婴儿" << std::endl;
}
if (age < 12) {
    std::cout << "儿童" << std::endl;
}
if (age < 18) {
    std::cout << "少年" << std::endl;
}
if (age < 60) {
    std::cout << "成年" << std::endl;
}
if (age >= 60) {
    std::cout << "老年" << std::endl;
}
⚠️
揭晓

wrong_order:顺序反了。age < 60 排在最前面, 5 岁、12 岁都满足这一条,于是统统被判成“成年”,更精确的分支再也没机会执行。

no_else:去掉了 else,每个 if 各自独立判断。 而这些条件本来就不互斥——5 岁同时满足 <12<18<60, 于是连续输出三行。

else if 链真正的意义:条件要按从特殊到一般排列,而且“命中就跳过其余”这条规则, 正是让分支彼此互斥的关键。

📖 理论讲解

else if 的真面目:嵌套 if

else if 链其实是嵌套 if 的简写——每个 else 后面紧跟一个 if,只是被代码格式“拉平”了,本质没变:

nested_if.cpp CPP
// 写法一:else if 链
if (score >= 90) {
    std::cout << "优秀" << std::endl;
} else if (score >= 60) {
    std::cout << "及格" << std::endl;
} else {
    std::cout << "不及格" << std::endl;
}

// 写法二:嵌套 if,和写法一完全等价
if (score >= 90) {
    std::cout << "优秀" << std::endl;
} else {
    if (score >= 60) {
        std::cout << "及格" << std::endl;
    } else {
        std::cout << "不及格" << std::endl;
    }
}
⚠️
嵌套时省略大括号:悬挂 else

既然 else if 本质是嵌套,那嵌套的 if 如果省略大括号, else 会配对给离它最近、还没被配对的 if—— 不一定是程序员以为的那个:

dangling_else.cpp CPP
int score = 75;   // 75 分,本该是“及格”

// 写法一:省略大括号——else 配对到最近的 if (score >= 90)
if (score >= 60)
    if (score >= 90)
        std::cout << "优秀" << std::endl;
    else
        std::cout << "不及格" << std::endl;
// 输出:不及格 —— 75 分被判成了不及格!

// 写法二:补上大括号——else 才配对到外层 if (score >= 60)
if (score >= 60) {
    if (score >= 90) {
        std::cout << "优秀" << std::endl;
    }
} else {
    std::cout << "不及格" << std::endl;
}
// 75 >= 60,进入大括号;90 不满足,什么都不输出——这才对

这也是为什么上节课建议大括号总是写上——嵌套层数一多,悬挂 else 很难一眼看出。

第二段

&& 和 ||:组合多个条件

📖 理论讲解

为什么需要组合条件

“成绩在 60 到 80 之间”——单靠一个比较运算符做不到,需要把两个条件合起来判断&&(与)要求两边都成立,||(或)只要一边成立:

aba && ba || b
1111
1001
0101
0000
range_and.cpp CPP
int score = 75;

if (score >= 60 && score < 80) {
    std::cout << "中等" << std::endl;     // 75 满足:>= 60 且 < 80
}
weekend_or.cpp CPP
int day = 6;

if (day == 6 || day == 7) {
    std::cout << "周末" << std::endl;     // 6 满足第一个条件,整体就是 true
}
💡
优先级
比较运算符(>= 等)的优先级高于 &&&& 又高于 ||。表达式复杂时不必死记,直接加括号最稳妥。
⚠️
陷阱:60 <= score <= 80 这样写对吗?

这行代码能编译通过,但意义完全不对:

chained_compare_trap.cpp CPP
int score = 95;

std::cout << (60 <= score <= 80) << std::endl;
// 计算顺序:先算 60 <= score,结果是 true(即 1)
// 再算 1 <= 80,结果还是 true
// 所以不管 score 是多少,几乎都输出 1!

std::cout << (score >= 60 && score <= 80) << std::endl;
// 这才是真正的“60 到 80 之间”,正确写法

根源还是上节课讲的条件本身是一个值——60 <= score 算出的 true/false(即 1/0)又被拿去跟 80 比较,跟“区间”毫无关系。

学有余力:短路求值
&&|| 会“算到能确定结果就停”:左边已经决定了整体结果, 右边就不会再算。这能避免一些错误:
short_circuit.cpp CPP
int a = 10, b = 0;

if (b != 0 && a / b > 2) {
    std::cout << "比较结果" << std::endl;
}
// b != 0 已经是 false,&& 后面的 a / b 不会再被计算
// 否则 a / b 就是除以 0,程序会出错
第三段

!:取反

📖 理论讲解

把条件反过来

! 放在条件前面,把 truefalsefalsetrue。常用于“校验输入是否不合法”这类场景:

not_operator.cpp CPP
bool isAdult = (age >= 18);

std::cout << !isAdult << std::endl;   // 取反:成年时输出 0,未成年时输出 1

if (!(score >= 0 && score <= 100)) {
    std::cout << "分数输入错误" << std::endl;
}

了解即可:!(a && b)!a || !b 是等价的(德摩根定律), 不要求记忆,遇到时知道怎么回事就好。

实战

动手做两个判断器

练习 6-1

温度分级

读入一个整数温度,按下表分五档输出:

  • 低于 0:寒冷
  • 0 到 10(不含 10):冷
  • 10 到 22(不含 22):凉爽
  • 22 到 30(不含 30):温暖
  • 30 及以上:炎热

要求:else if 链实现,不要用独立的 if

想一想
条件可以从“低到高”用 < 写,也可以从“高到低”用 >= 写—— 两种顺序都行,但顺序和比较方向必须搭配一致,否则就会遇到本节课开头的“顺序陷阱”。
练习 6-2

闰年判断器

读入一个年份,判断它是否为闰年。

闰年规则:能被 4 整除不能被 100 整除,或者能被 400 整除。

要求:用一个 if 条件,把 &&|| 组合起来表达这条规则(回忆第 2 讲的 % 取余)。

💡
提示
先分别写出“能被 4 整除且不能被 100 整除”和“能被 400 整除”两个子条件, 再用 || 连接。要不要给 && 部分加括号?试着去掉括号看看结果是否变化。
收尾

小结

📖 理论讲解

这节课你掌握了

能力用到的工具
三条以上路径选一条if / else if / else
判断顺序与互斥性从特殊到一般排列,命中即跳过其余
组合多个条件&&||
反转条件!

最该记住的一句话:else if 链一旦命中就跳过其余,所以条件的顺序和互斥性都很重要; 最该警惕的一个坑:60 <= score <= 80 在 C++ 里能编译,但意义不对。

💡
下节课预告
这节课的 else if&&,下节课会在一个完整项目里综合起来—— 写一个成绩等级判断器,把分数分成 A / B / C / D / E 五档。