文章

【信奥业余科普】C++ 的奇妙之旅 | 14:程序的分叉路口——逻辑判断与 if-else 语句

在上一篇文章中,我们探讨了计算机底层二进制存储的规则,了解了“爆 int”数据溢出与浮点数精度丢失的原因,并简单了解了条件控制。不过,我们目前编写的程序还有一个明显的问题:代码只能从上到下按顺序执行,不会根据情况改变执行路线。

如果在之前分苹果的程序中,用户输入的小朋友数量是 0,程序在执行除法时就会因为除数为零而引发崩溃报错。为了让程序能够应对各种情况,避开错误,我们需要引入一项基本机制:逻辑判断与条件控制语句(if-else)

写在前面的话:这是一系列专为对信奥(信息学奥赛)感兴趣的中小学生及家长朋友们准备的科普文章。笔者受自身学识所限,文中若存在不严谨之处,还望各位读者指正。

本系列文章往期回顾:

第二部分 【C++的奇妙之旅】


一、 判断的基础:布尔类型(bool)

在程序做出选择之前,首先要判断某个条件是否成立。

C++ 使用关系运算符(比如 > 大于、< 小于、>= 大于等于、== 判断相等、!= 不等于)来比较数值。

这些比较运算的结果,在我们第 11 篇文章中介绍过,是一种简单的数据类型——布尔值(bool

布尔类型只有两个明确的状态:

  • true(真):条件成立。
  • false(假):条件不成立。

背景知识:为什么叫“布尔”类型? 布尔(Boolean)这个名字是为了纪念 19 世纪的英国数学家乔治·布尔(George Boole)。他创立了“布尔代数”,第一次用数学公式推演了逻辑推理中的“真”与“假”。几十年后,人们惊奇地发现这种逻辑体系完美契合了计算机底层电路的通塞开关状况,于是这种代表真假的数据类型就被自豪地命名为“布尔型”。

在计算机底层的真实表现:

从纯理论上讲,在电脑里记录 truefalse 只需要占用 1 个比特(Bit,即一个电平信号 01)就够了。但实际上,为了方便数据高速读写,现代计算机能直接读取的最小内存单位是一个字节(Byte,等于 8 个比特)。

因此,在 C++ 和大多数主流编程语言中,设定一个 bool 变量通常会占据一整个 字节(1 Byte) 的空间。在底层的实际运转中,它遵循一个极其简单的判断规则:

  • 当这块内存储存的数据是数字 0 时,系统就认定它是 false
  • 当这块内存储存的是 任何非零数字(哪怕里面是个 99,通常系统自动生成时会填 1)时,系统都会直接将其视为 true 执行。

比如在执行 5 > 2 时,计算机比对后会得到真实存在的结果 true(在其底层记录位中写下数字 1)。正是系统分析出的这个小小 truefalse 凭证,主导了程序在下一个路口该分头走向哪里。

新手注意:赋值 = 和判断 == 初学者很容易犯一个错误:把用来判断相等的双等号 ==,写成单等号 =。 单等号 = 是“赋值”,也就是把一个值存入变量里;而双等号 == 才是用来比较两边是否相等的。如果在这里写错,不仅判断会失效,还会改掉变量原本的值,导致程序出错。

二、 if-else 判断语句的使用

有了布尔值之后,我们就可以用 if(如果条件为真)和 else(否则)来控制程序的路线了。

1. 它是如何工作的?

正常情况下,计算机是按顺序“读一行、做一行”来执行代码的。在 CPU(中央处理器)内部,有一个专门负责指路的微小零件叫做 “程序计数器(PC)”,它通常只会呆板地指向紧挨着的下一行代码的内存地址。

而当我们使用了判断语句,本质上是让编译器给 CPU 追加了一条非常特殊的机器指令——“条件跳转(Jump)指令”

遇到这个分岔口时,CPU 会优先检查括号内的判断条件:

  • 如果结果是 true(条件成立),CPU 就会顺应程序的默认惯性继续平稳往下运行,进入 if 后面的代码块(大括号 {} 里的内容),逐行处理里面的任务。
  • 如果结果是 false(条件不成立),系统底层就会强行拨动“程序计数器”的指针,发生一次跨越式的跳转(Jump):它会瞬间无视 if 内部的所有代码,将执行起点直接“空降”到 else 分支所在的代码范围,去处理那一套备用的解决方案。

正是由于底层地址能够被改变并发生跳跃,这种看似只会做死板算术题的硅基芯片,才真正拥有了能够根据实际情况做出不同应对的“非线性选择能力”。

2. 代码结构

下面是判断语句的基本写法:

1
2
3
4
5
if (条件结果 == true) {
    // 如果上面条件为真,执行这里的代码
} else {
    // 如果条件为假,执行这里的代码
}

三、 代码实战:升级分苹果程序

让我们稍微修改第 12 篇中的分苹果程序,加入 if-else。这样程序不仅能检查是否有剩余的苹果,还能在遇到小朋友人数为 0 时,提前给出提示,防止崩溃:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>

int main() {
    int total_apples;
    int kids;

    std::cout << "请输入苹果总数与小朋友人数(用空格隔开):";
    std::cin >> total_apples >> kids;

    // 安全检查:如果小朋友数量是 0,会报错
    if (kids == 0) {
        // 条件为 true 时执行
        std::cout << "错误:小朋友人数不能为 0!" << std::endl;
    }
    else {
        // 条件为 false,即人数不为 0 时执行核心计算
        int apples_per_kid = total_apples / kids; // 计算每人分几个
        int apples_left = total_apples % kids;    // 计算剩下几个

        // 进一步判断是否正好分完
        if (apples_left == 0) {
            // 余数为 0
            std::cout << "正好分完!每人分到 " << apples_per_kid << " 个。" << std::endl;
        } else {
            // 有剩余
            std::cout << "无法平分。每人分到 " << apples_per_kid << " 个,还剩下 " << apples_left << " 个苹果。" << std::endl;
        }
    }

    return 0; // 程序结束
}

结语

通过 if-else 条件控制语句,我们让程序拥有了判断能力,可以根据情况执行不同的代码,还能提前发现异常并给出提示。

然而,if-else 只能处理一次性的判断。如果我们想让程序多次重复执行某段操作(比如让系统连续不断地处理任务),一直用判断语句去写会非常麻烦。

要解决复杂的重复性问题,我们需要学习一种能够让机器自动重复执行代码的功能——循环结构(For / While 语句)。我们将在下一篇文章中详细介绍!

所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code

GESP 学习专题站:GESP WIKI

"luogu-"系列题目可在洛谷题库进行在线评测。

"bcqm-"系列题目可在编程启蒙题库进行在线评测。

欢迎加入Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答

欢迎加入C++ GESP/CSP认证学习QQ频道,考试资源总结汇总

欢迎加入C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助

GESP/CSP 认证学习微信公众号
GESP/CSP 认证学习微信公众号
本文由作者按照 CC BY-NC-SA 4.0 进行授权