默认情况下,C++ 程序是从上到下一行一行按顺序执行的。但在编写程序时,我们经常需要根据 “条件判断” 来决定执行哪一段代码,这种结构就叫做 “选择结构”。不管是单向选择、双向选择还是多向选择,程序在同一次判断中最终只会执行其中的一个分支。
在 C++ 中,选择结构主要有 2 种实现方式:一种是 if 语句,另一种是 switch 语句。这一节我们先来学习使用频率最高的 if 语句。
C++ if 语句
在 C++ 中,单向选择使用的是 if 语句。它的逻辑就像我们平时说的 “如果……就……”:只有当指定的条件成立时,才去执行对应的代码。如果条件不成立,就什么都不做。
语法:
if (条件) {
// 条件为 true 时执行的代码
}说明:
if 后面的小括号用来填写判断条件,最常见的就是比较表达式或逻辑表达式,比如 score >= 60。
当条件为 true(真)时,程序会进入花括号 {} 执行里面的代码。当条件为 false(假)时,则会直接跳过 {} 内部的代码,继续往下执行后面的程序。由一对花括号 {} 括起来的代码称为 “语句块”,C++ 会把它看作一个整体来执行。
此外,如果小括号里填写的是普通整数,C++ 会自动进行类型转换,将非 0 数值当作 true,将 0 当作 false。
示例 1:使用 if 语句
#include <iostream>
int main() {
int score = 85;
if (score >= 60) {
std::cout << "考试通过\n";
}
return 0;
}运行结果如下。
考试通过分析:
上面这个例子非常简单。score >= 60 表示判断变量 score 是否大于或等于 60。这里 score 的值为 85,条件返回 true,程序进入花括号输出 “考试通过”。如果把 score 改成 50,条件返回 false,花括号里的代码就会被跳过,屏幕什么也不会输出。
如果 if 语句内部只有一条执行语句,语法上是允许把花括号 {} 省略掉的。对于上面这个例子来说,下面 2 种方式是等价的:
// 方式 1(推荐)
if (score >= 60) {
std::cout << "考试通过\n";
}
// 方式 2
if (score >= 60) std::cout << "考试通过\n";哪怕 if 内部只有一条语句,我们也推荐大家统一使用方式 1。因为 C++ 只根据花括号 {} 来识别哪些代码属于 if,完全不看代码缩进。如果省略了 {},同时后面又写了多条语句,就很容易产生下面这种错觉:
int score = 50;
if (score >= 60)
std::cout << "考试通过\n";
std::cout << "继续加油\n";在上面这段代码中,虽然第二行输出也缩进了 4 个空格,但因为没有 {} 包裹,实际上只有第一行受 if 控制。当 score 为 50 时,第一行被跳过,第二行 “继续加油” 依然会照常输出。因此,平时写 if 语句时始终把 {} 写完整是最稳妥的习惯。
另外还要注意,if (条件) 的小括号后面千万不要多加英文分号(;)。一旦写成 if (score >= 60);,末尾的分号就会被当成一条空语句,导致 if 判断提前结束,后面的花括号代码不管条件是否成立都会执行。
C++ if...else 语句
单向的 if 语句只处理了条件成立的情况。如果条件成立和不成立时需要分别做不同的处理,我们可以在 if 后面加上 else 关键字,构成 “如果……否则……” 的双向选择。
语法:
if (条件) {
// 条件为 true 时执行的代码
} else {
// 条件为 false 时执行的代码
}说明:
if...else 语句相对 if 语句来说,只是多了一个 else 分支。当条件为 true 时,执行 if 后面花括号中的代码;当条件为 false 时,执行 else 后面花括号中的代码。这两个分支是互斥的,程序每次只会执行其中的一个。
示例 2:使用 if...else 语句
#include <iostream>
int main() {
int score = 55;
if (score >= 60) {
std::cout << "通过\n";
} else {
std::cout << "补考\n";
}
return 0;
}运行结果如下。
补考分析:
在这个例子中,变量 score 的值为 55,判断条件 score >= 60 返回 false,因此程序跳过 if 分支,直接执行 else 后面花括号中的代码,输出 “补考”。
需要注意的是,else 后面不需要也不能再写小括号条件,它会自动承接上方 if 条件不成立的所有情况。同时,else 必须紧跟在 if 分支之后,不能脱离 if 单独使用。
C++ if...else if...else 语句
很多实际问题并不止 “非此即彼” 两种情况。比如把考试成绩划分为优秀、良好、及格、不及格 4 个等级,这时我们就可以通过 else if 增加多个判断分支,构成多向选择。
语法:
if (条件 1) {
// 条件 1 为 true 时执行的代码
} else if (条件 2) {
// 条件 2 为 true 时执行的代码
} else {
// 以上条件都为 false 时执行的代码
}说明:
在多向选择中,中间的 else if 分支可以根据需要写一个、两个甚至更多个,末尾的 else 分支也可以按需省略。
程序运行时会从第一个 if 条件开始依次往下判断。一旦某个条件返回 true,就会执行对应分支的代码,然后直接退出整个 if 结构,后面的分支不再检查。只有前面所有条件都不满足时,才会执行末尾 else 里的代码。
示例 3:划分考试成绩等级
#include <iostream>
int main() {
int score = 86;
if (score >= 90) {
std::cout << "优秀\n";
} else if (score >= 80) {
std::cout << "良好\n";
} else if (score >= 60) {
std::cout << "及格\n";
} else {
std::cout << "不及格\n";
}
return 0;
}运行结果如下。
良好分析:
这里变量 score 的值为 86。程序先判断第一个条件 score >= 90 得到 false,接着判断第二个条件 score >= 80 得到 true,于是输出 “良好” 并直接退出整个分支结构,后面的分支都不会再执行。
可能有些小伙伴会问:“第二个条件为什么只写 score >= 80,而不用写成 score >= 80 && score < 90 呢?”
其实原因很简单:程序之所以能走到第二个分支,本身就已经说明第一个条件 score >= 90 不成立了。此时分数必然小于 90,因此只需要继续判断是否大于或等于 80 就可以了。
也正因为程序是从上往下依次判断的,编写 else if 时条件的排列顺序非常关键。如果把范围最宽的 score >= 60 放到最前面,下面这种写法结果就会出错:
if (score >= 60) {
std::cout << "及格\n";
} else if (score >= 80) {
std::cout << "良好\n";
} else if (score >= 90) {
std::cout << "优秀\n";
}假设此时 score 是 95,它在第一个条件 score >= 60 处就直接满足并输出 “及格” 退出了,后面的 80 分和 90 分分支根本没有机会执行。因此,按数值划分区间时,我们要顺着从高到低或从低到高的顺序排列,先写范围最严格的条件,再一步步往下放宽。
此外,初学的小伙伴还容易把 “多个独立的 if 语句” 和 “if...else if 分支链” 搞混。如果把上面例子中的 else 去掉,全改成独立的 if,结果又会怎样呢?我们来看下面这个例子。
示例 4:多个独立 if 的执行效果
#include <iostream>
int main() {
int score = 95;
if (score >= 60) {
std::cout << "及格\n";
}
if (score >= 80) {
std::cout << "良好\n";
}
if (score >= 90) {
std::cout << "优秀\n";
}
return 0;
}运行结果如下。
及格
良好
优秀分析:
从运行结果可以看出,当 score 为 95 时,“及格”、“良好”、“优秀” 这 3 行内容全部被打印出来了。这是因为上面写了 3 个彼此独立的 if 语句,中间没有 else 连接,程序会把每一个 if 都单独判断一遍,只要条件成立就会执行。
简单来说,多个独立的 if 是 “满足几个就执行几个”,而 if...else if...else 是一条互斥的分支链,“只要命中一个,后面的分支就全部跳过”。
C++ if 语句的嵌套
在 C++ 中,if 语句还支持嵌套使用,也就是在一个 if 或 else 分支的花括号内部,再放入另一个 if 语句,用来处理有先后前提的多层判断。
语法:
if (条件 1) {
if (条件 2) {
// 条件 1 和条件 2 都为 true 时执行
} else {
// 条件 1 为 true、条件 2 为 false 时执行
}
} else {
// 条件 1 为 false 时执行
}说明:
对于嵌套的 if 语句,我们只需要从外到内根据条件一层层去判断,就像剥洋葱一样:只有外层条件成立并进入外层花括号之后,里面的内层 if 才会有机会执行。
在语法上,else 总是与离它最近且尚未配对的 if 相配对。平时写全花括号 {} 并保持规范的 4 空格缩进,就能一眼看清各个分支的层级关系。
示例 5:if 语句的嵌套
#include <iostream>
int main() {
int age = 20;
bool hasTicket = true;
if (age >= 18) {
if (hasTicket) {
std::cout << "可以入场\n";
} else {
std::cout << "请先购票\n";
}
} else {
std::cout << "未达到入场年龄\n";
}
return 0;
}运行结果如下。
可以入场分析:
在这个例子中,变量 age 为 20,外层条件 age >= 18 成立,程序进入外层花括号继续判断内层的 hasTicket。由于 hasTicket 本身就是 bool 类型,直接写 if (hasTicket) 就等价于 if (hasTicket == true),因此最终输出 “可以入场”。
如果把 age 的值改为 15,外层条件 age >= 18 返回 false,程序就会直接执行最外层的 else 分支输出 “未达到入场年龄”,不会再检查里面的 hasTicket。
在实际开发中,只有当外层条件和内层条件不满足时需要分别给出不同处理,我们才使用嵌套 if。如果只是想在两个条件同时满足时执行同一段代码,直接使用逻辑与写成 if (age >= 18 && hasTicket) 会简洁得多。
if 条件常见易错点
在编写 if 小括号里的判断条件时,有两个语法上不会报错、但运行结果完全不对的常见易错点,小伙伴们要格外留意:
误把相等判断写成赋值:如果把双等号误写成单个等号,比如写成 if (a = 10),程序会先把 10 赋给 a,整个表达式的结果就是 10。接着非 0 整数 10 被自动当作 true,导致条件永远成立。判断相等一定要认准双等号 ==。
照搬数学连写不等式:判断成绩是否在 60 到 100 之间时,不能写成 if (60 <= score <= 100)。比如当 score 为 50 时,程序从左往右先算 60 <= 50 得到 false,在比较运算中相当于整数 0,再算 0 <= 100 反而得出 true。判断数值区间必须使用逻辑运算符 && 连接,写成 if (score >= 60 && score <= 100)。
