上一课标准答案:
-
输出:
0
1
2
因为当 i == 3 时执行:
break;
整个循环直接结束。
-
输出:
0
1
2
4
因为当 i == 3 时:
continue;
只跳过这一轮,所以后面的 4 还会继续执行。
-
最大区别:
break
= 整个循环直接结束continue
= 只跳过当前这一轮,下一轮继续 -
这段代码:
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);
是什么意思?