
上一课标准答案最后输出5因为change(x)只是把x的值复制给参数a函数里改的是副本。依次输出13 3原因是函数内部number 10;把副本number从 3 改成 13所以先输出 13。但外面的x没有改变仍然是 3。因为void change(int a)采用的是值传递。a是x的副本不是x本身。一句话值传递就是把外部变量的值复制一份给函数参数函数修改副本不会影响原变量。第 14 课引用这一课非常重要。前面我们遇到的问题是void change(int a) { a 100; } int main() { int x 5; change(x); std::cout x std::endl; }最终x 5因为x → 复制一份 → a但现在我就是想让函数直接修改原来的x怎么办C 可以使用这就是引用 reference1. 先看效果把void change(int a)改成void change(int a)完整代码#include iostream void change(int a) { a 100; } int main() { int x 5; change(x); std::cout x std::endl; return 0; }这次输出100为什么只增加了一个结果就完全不一样2. 值传递给你一张复印件以前void change(int a)可以想象成main x ┌─────┐ │ 5 │ └─────┘ │ │ 复制 ▼ change a ┌─────┐ │ 5 │ └─────┘所以a 100;只改变下面那个盒子x 5 a 1003. 引用不是复印而是给原变量起“别名”现在void change(int a)可以把a理解成x的另一个名字。调用change(x);之后可以粗略想象成┌─────────┐ x ─────→│ 5 │ └─────────┘ ↑ │ a这里x和a不是两个盒子。而是两个名字指向同一个变量。所以a 100;其实就是在改x 100;最终外面的x也变了。4. 最重要的对比值传递void change(int a)含义给函数一个副本修改a不会影响原变量。引用传递void change(int a)含义让参数 a 直接代表原来的变量修改a原变量也会变化。5.到底放在哪里看int a现在先把它整体理解成a是一个int类型的引用。不是int a而是int a多了这告诉 C不要创建新的整数副本a要引用外面的那个整数。6. 一个简单例子void addOne(int number) { number; }然后int main() { int count 10; addOne(count); std::cout count std::endl; }执行count 10调用addOne(count);此时number就是count的引用。然后number;实际上修改count10 → 11所以最后输出117. 机器人例子真正修改速度上一课我们写void stopMotor(double speed) { speed 0.0; }这个不能改变外面的速度。现在改成void stopMotor(double speed) { speed 0.0; }然后int main() { double motor_speed 100.0; stopMotor(motor_speed); std::cout motor_speed std::endl; }最后motor_speed 0这次是真的改到了原变量。8. 用“遥控器”来理解引用值传递像拍了一张机械臂当前状态的照片给函数。函数在照片上画来画去不影响真实机械臂。引用则像把真实机械臂的控制权交给函数。函数一修改speed 0;真实外部变量也改变。这个区别你以后一定要记住。9. 引用本身也可以在普通代码里创建不只是函数参数可以用引用。例如int x 5; int y x;这里y是x的引用。可以理解成x ─────┐ ▼ ┌──────┐ │ 5 │ └──────┘ ▲ y ─────┘所以y 20;以后x 20 y 20因为它们实际上对应同一个东西。10. 看完整程序#include iostream int main() { int x 5; int y x; y 20; std::cout x std::endl; std::cout y std::endl; return 0; }输出20 2011. 引用不是“复制值”这一点特别关键。int x 5; int y x;和int x 5; int y x;完全不同。第一种int y x;得到两个变量x 5 y 5之后y 100;结果x 5 y 100互不影响。第二种int y x;y是x的引用。执行y 100;结果x 100 y 10012. 引用创建时通常必须绑定变量例如int x 5; int y x;这里创建y的同时就告诉它你引用x。不能像普通变量那样随便理解成int y;然后以后再说引用谁。对于普通引用通常创建时就必须绑定目标。现在先记住这一点即可。13. 引用一旦绑定通常不能“换人”看int x 5; int z 10; int ref x;这里ref绑定的是x如果后面写ref z;初学者可能以为ref 改成引用 z。不是。实际上是把z的值赋给ref所引用的x。因为z 10所以x 变成 10引用本身仍然是x的别名。这个以后再深入。14. 为什么 C 需要引用最直接的原因有两个。第一需要修改外部变量例如void reset(double angle) { angle 0.0; }第二以后处理很大的对象时避免复制比如以后你有std::vectordouble里面可能有大量数据。如果每次传函数都完整复制一份会浪费时间和内存。所以以后经常会看到void process(std::vectordouble data)甚至void process(const std::vectordouble data)这里又出现了const以后我们会专门学。现在只需要知道引用不仅能修改外部变量还能避免不必要的数据复制。15. 真实机械臂代码会经常见到以后可能看到void updateJointAngle(double angle)或者void calculateIK(double x, double y, double z, double joint1, double joint2, double joint3)这里前三个x y z可能只是输入。而joint1 joint2 joint3使用引用是因为函数需要把计算结果直接写出去。例如joint1 30.0; joint2 45.0; joint3 -20.0;那么外部对应的关节变量也会改变。16. 一个简单的 IK 风格例子先不管真实运动学只模拟void calculateAngles(double joint1, double joint2) { joint1 30.0; joint2 45.0; }然后int main() { double j1 0.0; double j2 0.0; calculateAngles(j1, j2); std::cout j1 std::endl; std::cout j2 std::endl; }输出30 45因为joint1 引用 j1 joint2 引用 j2函数直接修改了j1 j217. 参数是值还是引用只差一个非常值得对比。值传递void change(int a)复制引用传递void change(int a)直接操作原变量所以你以后看到函数参数double angle和double angle一定要意识到行为可能完全不同。18. 一个非常重要的安全意识引用很方便但也意味着函数可以修改你的原变量。例如void test(int x) { x -999; }外面int motor_speed 100; test(motor_speed);结果motor_speed -999所以以后看到要多一个意识这个函数有没有可能修改我传进去的变量这对阅读真实工程代码非常重要。19. 今天先不要把和“地址”混在一起你可能以后会听说 可以取地址确实如此。但是同一个符号在不同位置可能有不同含义。今天我们只学习int a这里的表示引用“取地址”我们学习指针时再讲否则现在很容易混乱。20. 本课核心图值传递x ┌───┐ │ 5 │ └───┘ │ │复制 ▼ a ┌───┐ │ 5 │ └───┘引用x ───┐ ▼ ┌─────┐ │ 5 │ └─────┘ ▲ a ───┘这个图如果真正理解了引用就掌握一半了。本课小练习第 1 题void change(int a) { a 20; } int main() { int x 5; change(x); std::cout x std::endl; }最终输出什么第 2 题int x 10; int y x; y 30;最后x ? y ?第 3 题下面两种写法有什么本质区别void test(int a)和void test(int a)第 4 题void setZero(double angle) { angle 0.0; }如果double joint1 45.0; setZero(joint1);最后joint1是多少