← 课程目录
第 13 讲 模块四:用函数组织代码

实战:函数版计算器

13 / 24
💡
本节课目标
今天不学新语法,把模块四的函数定义、调用、参数、返回值全部用进一个完整程序。 我们分四步搭这个计算器:先跑通一种运算,再补齐另外三个函数, 然后加上运算符分支,最后处理除以 0 这种意外情况。
开场

模块四回顾

📖 理论讲解

第 11~12 讲

第 11 讲:函数的定义与调用,用参数让函数按不同数据办事, 分清形参实参

第 12 讲:返回值,让函数不只是做事,还能把算出来的结果交回调用处, 供后续计算使用。

今天把两者拼在一起,做一个真正有用的小工具——四则运算计算器。

需求

计算器要做什么

📖 理论讲解

功能说明

  • 依次输入第一个数、运算符、第二个数。
  • 支持 + - * / 四种运算,各自封装成一个函数。
  • 除法时,如果除数是 0,提示错误,不进行运算。
  • 运算符不是这四种之一,提示“不支持的运算符”。
  • 合法时输出完整算式和结果,比如 3 + 4 = 7
第一步

先跑通一种运算

📖 理论讲解

别一口气写完,先写一小步

直接把四个运算符、四个函数、除零校验全部一次写完,很容易中途出错还不知道错在哪。 更稳妥的办法是:先只实现加法,确认“输入两个数 → 调用函数 → 输出结果” 这条链路能跑通,再一步步往上加。

calculator_step1.cpp CPP
#include <iostream>

double add(double a, double b) {
    return a + b;
}

int main() {
    double num1, num2;
    std::cout << "请输入第一个数:";
    std::cin >> num1;
    std::cout << "请输入第二个数:";
    std::cin >> num2;

    double result = add(num1, num2);
    std::cout << num1 << " + " << num2 << " = " << result << std::endl;
    return 0;
}
⚡ 动手实操 约 5 分钟

先跑通这一小步

calculator_step1.cpp 跑起来,输入几组数字,确认加法结果正确。 确认没问题后,再往下看怎么扩展成完整计算器。

第二步

补齐另外三个函数

📖 理论讲解

每种运算各自一个函数

加法能跑通,减乘除照着同样的样子各写一个函数就行——参数一样是两个 double,函数体里换成对应的运算符:

four_ops.cpp CPP
double add(double a, double b) {
    return a + b;
}

double subtract(double a, double b) {
    return a - b;
}

double multiply(double a, double b) {
    return a * b;
}

double divide(double a, double b) {
    return a / b;
}

四个函数各自逻辑很简单,封装成函数的好处不在“省代码”,而在于让 main 只关心“该调用哪个函数”,不用把具体计算和输入输出交互揉在一起。

第三步

加上运算符分支

📖 理论讲解

用 char 存运算符,多分支挑函数

运算符用 char 类型的变量 op 接收,再用模块二的 if / else if 多分支,根据 op 的值决定调用哪个函数:

branch_skeleton.cpp CPP
char op;
std::cin >> op;

if (op == '+') {
    result = add(num1, num2);
} else if (op == '-') {
    result = subtract(num1, num2);
} else if (op == '*') {
    result = multiply(num1, num2);
} else if (op == '/') {
    result = divide(num1, num2);
} else {
    std::cout << "错误:不支持的运算符" << std::endl;
}

这是骨架,还差一件事——除法万一遇到除数 0 怎么办?下一步专门处理。

第四步

处理除以 0

📖 理论讲解

校验放在调用函数之前

除以 0 的校验放在main 里、调用 divide 之前——函数只管“怎么算”,“能不能算”这件事交给主流程判断。 再用一个 bool valid 标记,记录这次输入到底能不能算出结果。

这是为了突出本课主流程而采用的简化设计,并不是唯一的组织方式。在更大的程序里, 还要考虑怎样让 divide 本身不会被其他调用者错误地用于除以 0

实现

拼起来:完整代码

calculator.cpp CPP
#include <iostream>

double add(double a, double b) {
    return a + b;
}

double subtract(double a, double b) {
    return a - b;
}

double multiply(double a, double b) {
    return a * b;
}

double divide(double a, double b) {
    return a / b;
}

int main() {
    double num1, num2;
    char op;

    std::cout << "请输入第一个数:";
    std::cin >> num1;
    std::cout << "请输入运算符(+ - * /):";
    std::cin >> op;
    std::cout << "请输入第二个数:";
    std::cin >> num2;

    double result;
    bool valid = true;

    if (op == '+') {
        result = add(num1, num2);
    } else if (op == '-') {
        result = subtract(num1, num2);
    } else if (op == '*') {
        result = multiply(num1, num2);
    } else if (op == '/') {
        if (num2 == 0) {
            std::cout << "错误:除数不能为 0" << std::endl;
            valid = false;
        } else {
            result = divide(num1, num2);
        }
    } else {
        std::cout << "错误:不支持的运算符" << std::endl;
        valid = false;
    }

    if (valid) {
        std::cout << num1 << " " << op << " " << num2 << " = " << result << std::endl;
    }

    return 0;
}
逐段看

main 里没有直接执行加减乘除计算,而是把计算委托给四个函数—— 这正是“用函数组织代码”的意义:main 只管流程(读输入 → 选分支 → 调函数 → 输出), “怎么算”交给函数负责。

valid 这个标记记录“这次输入是否可以算出结果”——除数为 0 或运算符不支持时都设成 false,最后用 if (valid) 决定要不要打印结果,这和第 10 讲猜数字游戏里 win 标记的思路是一样的。

💡
想一想:num2 == 0 这样比较靠谱吗
num2double。第 7 讲练习里提到过浮点数比较的坑—— 如果 num2 是运算得来的 0.0000001 这种“几乎是 0”的值, 这里的判断还成立吗?这节课先不深究,记住这是个待挖的坑就好。
测试

把每条分支都走一遍

⚡ 动手实操 约 15 分钟

按清单逐项验证

跑起来,依次测试下面的输入组合,确认输出符合预期:

输入期望输出
3 + 43 + 4 = 7
10 - 410 - 4 = 6
6 * 76 * 7 = 42
7 / 27 / 2 = 3.5
5 / 0错误:除数不能为 0
3 ^ 4错误:不支持的运算符
拓展

让计算器更完整

练习 13-1

正负零提示

算完结果后,再多打印一行:根据 result 的正负,提示“结果是正数” “结果是负数”或“结果是零”。

提示:不需要新函数,在 main 里加一段 if / else 就够了。

练习 13-2

把校验也封装成函数

写一个 bool isValidOperator(char op),返回这个运算符是否是 + - * / 之一。main 里先调用它判断,再进入运算分支。

练习 13-3

加一个乘方运算

写一个函数 power(double base, int exp),用循环算出 baseexp 次方,把运算符 ^ 接进 main 的分支里。 本练习只处理 exp >= 0 的整数。

提示:累乘器从 1 开始,循环 exp 次;因此 exp == 0 时不进入循环,结果正好是 1

练习 13-4

算完一次,问要不要继续

给整个计算流程套一层外层循环:算完一次,提示“输入 y 继续,其它任意键退出”, 直到用户选择退出为止。

💡
想一想
这层“要不要继续”的循环,次数取决于用户——该用 for 还是 while?回到第 9 讲的挑选标准。
小结

模块四回顾

📖 理论讲解

第 11~13 讲,你掌握了

讲次核心内容
第 11 讲函数定义与调用、参数、形参 / 实参
第 12 讲返回值 return、返回值参与运算
第 13 讲综合实战:四个函数 + 主流程调度

到这里,程序已经能判断、能重复、还能把逻辑 拆分成一个个函数——这是写更大程序必备的组织能力。

💡
下节课预告
目前每次只能处理一两个数据,如果要处理“全班 30 个人的成绩”呢? 一个个声明变量显然不现实。模块五学数组vector, 批量存储和处理数据。