C++ 第 10 课:函数 Function

上一课标准答案:

  1. 输出:

    0
    1
    2

因为当 i == 3 时执行:

复制代码
break;

整个循环直接结束。

  1. 输出:

    0
    1
    2
    4

因为当 i == 3 时:

复制代码
continue;

只跳过这一轮,所以后面的 4 还会继续执行。

  1. 最大区别:

    break
    = 整个循环直接结束

    continue
    = 只跳过当前这一轮,下一轮继续

  2. 这段代码:

    int i = 0;

    while (i < 5)
    {
    if (i == 2)
    {
    continue;
    }

    复制代码
     i++;

    }

当 i 增加到 2 后:

复制代码
continue;

会导致下面的:

复制代码
i++;

被跳过。

于是 i 永远等于 2:

复制代码
i = 2
↓
2 < 5
↓
true
↓
continue
↓
i 还是 2
↓
继续循环......

所以形成死循环。


第 10 课:函数 Function

现在开始进入一个非常重要的新阶段。

前面我们的代码都喜欢写在:

复制代码
int main()
{
    // 所有代码
}

里面。

程序稍微复杂一点,就会变成:

复制代码
int main()
{
    // 读取机械臂状态
    // 计算角度
    // 判断限位
    // 控制电机
    // 控制夹爪
    // 读取传感器
    // 输出日志
    // ...
}

最后可能几百、几千行。

这样代码会非常难看懂。

所以 C++ 提供了:

函数 function


1. 函数最直觉的理解

你可以把函数理解成:

给一组操作起一个名字。

比如机械臂有一个动作:

复制代码
打开夹爪

如果不用函数,可能每次都要写一堆控制代码。

我们可以把这些代码打包,起名:

复制代码
openGripper()

以后想打开夹爪,只需要:

复制代码
openGripper();

就行了。

所以:

复制代码
函数
≈
一段有名字、可以重复使用的代码

2. 生活类比

你去咖啡机按:

复制代码
"制作咖啡"

你不会自己执行:

复制代码
磨豆
加热水
控制压力
萃取
停止

你只按一个按钮:

复制代码
制作咖啡()

咖啡机内部帮你执行一整套步骤。

函数就是这种感觉。


3. 第一个最简单的函数

看:

复制代码
#include <iostream>

void sayHello()
{
    std::cout << "Hello" << std::endl;
}

int main()
{
    sayHello();

    return 0;
}

这已经出现很多新东西了,我们一点点拆。


4. sayHello() 是什么?

这里:

复制代码
sayHello

是我们自己起的函数名。

和变量名字类似:

复制代码
int age;

变量叫:

复制代码
age

而:

复制代码
sayHello()

函数叫:

复制代码
sayHello

括号:

复制代码
()

表示这是一个函数。


5. 这一整块是在"定义函数"

复制代码
void sayHello()
{
    std::cout << "Hello" << std::endl;
}

可以理解为:

我现在创建一个函数,它的名字叫 sayHello。

函数内部要做的事情是:

复制代码
std::cout << "Hello" << std::endl;

所以:

复制代码
sayHello()
↓
输出 Hello

6. void 是什么?

这里出现:

复制代码
void

先把它理解成:

这个函数执行完以后,不需要返回一个结果。

你之前见过:

复制代码
int main()

里面的 int 表示:

这个函数会返回一个整数。

所以最后有:

复制代码
return 0;

而:

复制代码
void sayHello()

表示:

sayHello 只负责做事情,不返回数据。

暂时记:

复制代码
void
= 没有返回值

7. 什么叫"调用函数"?

定义好:

复制代码
void sayHello()
{
    std::cout << "Hello" << std::endl;
}

以后在 main() 里面:

复制代码
sayHello();

这叫:

调用函数

意思是:

去执行 sayHello 函数里面的代码。

所以:

复制代码
int main()
{
    sayHello();

    return 0;
}

执行顺序:

复制代码
进入 main
↓
遇到 sayHello()
↓
跳到 sayHello 函数
↓
输出 Hello
↓
sayHello 执行结束
↓
回到 main
↓
return 0

8. 如果调用三次呢?

复制代码
int main()
{
    sayHello();
    sayHello();
    sayHello();

    return 0;
}

输出:

复制代码
Hello
Hello
Hello

这就是函数的一个巨大作用:

同一段代码可以重复使用。


9. 开始往机械臂靠

我们可以写:

复制代码
void stopMotor()
{
    std::cout << "Motor stopped" << std::endl;
}

然后:

复制代码
int main()
{
    stopMotor();

    return 0;
}

未来真实代码里:

复制代码
stopMotor();

内部可能不是打印文字,而是:

复制代码
发送 CAN 指令
↓
目标速度设为 0
↓
驱动器停止电机

但是上层代码只需要看到:

复制代码
stopMotor();

马上就知道:

停止电机。

这就是函数为什么能让工程代码更清晰。


10. 为什么不把所有东西写在 main()?

比如:

复制代码
int main()
{
    std::cout << "Read encoder" << std::endl;
    std::cout << "Calculate angle" << std::endl;
    std::cout << "Move motor" << std::endl;

    std::cout << "Read encoder" << std::endl;
    std::cout << "Calculate angle" << std::endl;
    std::cout << "Move motor" << std::endl;
}

非常重复。

我们可以变成:

复制代码
void controlRobot()
{
    std::cout << "Read encoder" << std::endl;
    std::cout << "Calculate angle" << std::endl;
    std::cout << "Move motor" << std::endl;
}

然后:

复制代码
int main()
{
    controlRobot();
    controlRobot();

    return 0;
}

结构就清晰很多。


11. 函数可以接收数据

刚才:

复制代码
sayHello()

括号里面什么都没有。

但以后我们希望:

让函数根据不同数据做不同事情。

例如:

复制代码
void moveJoint(int joint)
{
    std::cout << joint << std::endl;
}

这里第一次出现:

复制代码
int joint

放在括号里面。

它叫:

参数 parameter


12. 参数是什么?

你可以把函数想成一个机器:

复制代码
输入
 ↓
函数
 ↓
执行某些操作

例如:

复制代码
void moveJoint(int joint)

表示:

moveJoint 需要别人给它一个整数。

这个整数会被存到:

复制代码
joint

里面。


13. 调用时给参数

例如:

复制代码
moveJoint(3);

那么相当于:

复制代码
把 3 传给 moveJoint
↓
joint = 3

于是:

复制代码
void moveJoint(int joint)
{
    std::cout << joint << std::endl;
}

输出:

复制代码
3

14. 完整程序

复制代码
#include <iostream>

void moveJoint(int joint)
{
    std::cout << "Move joint " << joint << std::endl;
}

int main()
{
    moveJoint(1);
    moveJoint(3);
    moveJoint(6);

    return 0;
}

输出:

复制代码
Move joint 1
Move joint 3
Move joint 6

注意:

我们只写了一份:

复制代码
void moveJoint(int joint)

却可以传进去:

复制代码
1
3
6

不同数据。


15. 函数可以有多个参数

例如机械臂需要:

哪个关节 + 转到多少度。

可以写:

复制代码
void moveJoint(int joint, double angle)
{
    std::cout << "Joint: " << joint << std::endl;
    std::cout << "Angle: " << angle << std::endl;
}

调用:

复制代码
moveJoint(2, 45.5);

意思就是:

复制代码
joint = 2
angle = 45.5

16. 参数之间为什么有逗号?

这里:

复制代码
void moveJoint(int joint, double angle)

两个参数:

复制代码
int joint
double angle

用:

复制代码
,

分开。

就像告诉函数:

我要给你两样东西。

第一个是整数:

复制代码
joint

第二个是小数:

复制代码
angle

17. 调用时顺序很重要

定义:

复制代码
void moveJoint(int joint, double angle)

调用:

复制代码
moveJoint(2, 45.5);

对应关系:

复制代码
2
↓
joint

45.5
↓
angle

所以顺序不能随便乱。


18. 机器人里会大量使用这种函数

以后你非常可能看到:

复制代码
moveJoint(1, 30.0);

setSpeed(100.0);

openGripper();

readEncoder();

calculateIK();

这些本质都是:

函数调用。

以后你第一次拿到真实机械臂源码时,很多代码之所以看起来"陌生",只是因为里面全是别人定义好的函数名。

例如:

复制代码
robot.connect();
robot.enable();
robot.moveJoint();

后面学类的时候我们会解释为什么前面又多了:

复制代码
robot.

现在先别管。


19. void 函数目前的结构

现在记住最简单格式:

复制代码
void 函数名()
{
    函数要执行的代码
}

例如:

复制代码
void stopRobot()
{
    std::cout << "Stop" << std::endl;
}

如果有参数:

复制代码
void 函数名(类型 参数名)
{
}

例如:

复制代码
void setSpeed(double speed)
{
    std::cout << speed << std::endl;
}

20. 一个小机械臂程序

复制代码
#include <iostream>

void moveJoint(int joint, double angle)
{
    std::cout << "Move joint " << joint << std::endl;
    std::cout << "Target angle " << angle << std::endl;
}

void stopRobot()
{
    std::cout << "Robot stopped" << std::endl;
}

int main()
{
    moveJoint(1, 30.0);
    moveJoint(2, 45.0);

    stopRobot();

    return 0;
}

你现在已经能大概读懂:

复制代码
进入 main
↓
调用 moveJoint
把 1 和 30.0 传进去
↓
再调用 moveJoint
把 2 和 45.0 传进去
↓
调用 stopRobot
↓
程序结束

这已经开始非常像工程程序的结构了。


本课小练习

第 1 题

复制代码
void hello()
{
    std::cout << "Hi" << std::endl;
}

int main()
{
    hello();
    hello();

    return 0;
}

输出几次 Hi?

第 2 题

复制代码
void printNumber(int number)
{
    std::cout << number << std::endl;
}

int main()
{
    printNumber(5);
}

输出什么?

第 3 题

下面:

复制代码
void moveJoint(int joint, double angle)

有几个参数?

它们分别是什么类型?

第 4 题

用自己的话解释:

复制代码
moveJoint(2, 30.5);

是什么意思?

相关推荐
Zootopia6261 小时前
快递无人车与无人机各自进入配送网络后,路线能否一起算?
c++·人工智能·机器学习·matlab·ai·机器人·无人机
朝朝辞暮i1 小时前
C++ 第7课 while 循环
开发语言·c++·算法
小朱爱编程1231 小时前
我用 Jev 做了三个实用工具:整理标签页、分诊飞书反馈、找回 GitHub 收藏
java·开发语言·人工智能·后端·python·架构·ai编程
谢亮_vipxieliang2 小时前
Java 8/11/17/21/25 怎么选?一篇讲清 LTS 升级路线
java·开发语言
Cindy_cd2 小时前
IDEA2021 配置 JDK+Maven
java·开发语言·maven
mmsx3 小时前
Android Dialog 插槽模式:用一套壳统一全应用的弹窗风格
android·java·dialog·开发语言
huanbailu3 小时前
Qt 跨线程信号槽:connect 返回 true 但槽函数不执行的坑
开发语言·c++·qt·信号槽·跨线程·元类型
ZealSinger3 小时前
Go slog生产落地LevelVar与共存
开发语言·后端·golang·go
落魄实习生3 小时前
Agent Scope Java 2.x 系列【11】AgentState 与状态存储
java·开发语言·ai