
上一课标准答案最终输出20因为void change(int a)中的a是x的引用修改a就是在修改原来的x。x 30 y 30因为int y x;表示y是x的别名它们对应同一个变量。本质区别void test(int a)是值传递把原变量的值复制一份给a修改a不影响原变量。而void test(int a)是引用传递a直接引用原变量修改a会修改原变量。最后joint1 0.0因为setZero(joint1);把joint1通过引用传进函数函数里的angle 0.0;直接修改了joint1。第 15 课指针*与地址这节是 C 里第一个真正容易绕晕人的知识点。但我们不背定义。我们先回答一个最基础的问题变量到底放在哪里1.int x 5;到底发生了什么你现在已经知道int x 5;可以粗略理解成x ┌─────┐ │ 5 │ └─────┘但这个“盒子”实际上不是凭空存在的。它要放在电脑的内存 RAM里面。你可以把内存想象成一排非常非常多的小房间。内存 地址1000 地址1004 地址1008 地址1012 ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ │ │ │ │ │ │ │ └──────┘ └──────┘ └──────┘ └──────┘每一块位置都有自己的地址就像现实中的房子有门牌号。2. 变量名和地址不是一回事假设int x 5;电脑可能把x放在某个内存位置。比如为了理解我们假设变量名x 内存地址1000 内容5那么可以画x ↓ 地址 1000 ┌──────────┐ │ 5 │ └──────────┘这里x是你给变量起的名字。而1000是它真正位于内存中的地址。现实程序里的地址不会这么简单可能长得像0x7ffd1234abcd现在先不用管。3. 地址就像门牌号这是理解指针最好的类比之一。假设杭州某小区 3栋502室这是一个地址。房间里面住着一个人。对应 C地址 ↓ 内存中的位置 值 ↓ 这个位置里面存放的数据所以int x 5;可以想成门牌号1000 房间内容54. 怎么知道x的地址C 可以写x注意这里的和上一课的int y x;虽然符号一样但位置不同意义也不同。这里x表示取得变量 x 的地址。5. 看一个程序#include iostream int main() { int x 5; std::cout x std::endl; std::cout x std::endl; return 0; }第一句std::cout x std::endl;输出的是5第二句std::cout x std::endl;输出的是x在内存中的地址。你可能看到类似0x7ffdf2817a4c每次运行甚至可能不一样。现在不需要解释为什么。6. 两种千万先分开目前你遇到两种第一种int y x;这里表示y是一个引用。第二种x这里表示取得x的地址。你可以先根据位置区分int y ↑ 声明引用 x ↑ 获取地址以后会逐渐习惯。7. 那“指针”是什么终于到了核心。假设int x 5;而x能获得x的地址。那么我们能不能创建一个变量专门保存这个地址可以。这就是指针 pointer例如int* p x;第一次看到很怪。我们一点点拆。8.int* p x;先看右边x意思x的地址。假设x 1000然后int* p表示创建一个指针变量名字叫p。它用来保存一个int类型变量的地址。所以int* p x;可以翻译成创建一个指向int的指针p让它保存x的地址。9. 画出来就非常直观了int x 5; int* p x;可以想成x 地址1000 ┌─────┐ │ 5 │ └─────┘ ▲ │ │ p里面存着1000 │ p ┌──────┐ │ 1000 │ └──────┘也就是说p不是存5。而是存x在哪里。这就是指针。10. 一句话理解指针指针就是一个专门保存内存地址的变量。普通变量int x 5;里面放5指针变量int* p x;里面放x 的地址11.*又是什么现在出现第二个核心符号*p如果p里面存的是x的地址那么*p意思就是根据p保存的地址找到那个位置里面的数据。这个操作叫解引用 dereference暂时不用背英文。你可以把*p理解成“顺着 p 找过去看看里面是什么。”12. 举例int x 5; int* p x;现在p 存着 x 的地址所以*p就是5例如std::cout *p std::endl;输出513. 现在我们有三个不同的东西假设int x 5; int* p x;那么x表示x里面的值也就是5x表示x的地址例如假设1000p表示p里面保存的内容而p保存的就是1000*p表示去p指向的位置取值于是得到5所以x → 5 x → 1000 p → 1000 *p → 5这是本课最核心的关系。14. 为什么*p能修改x看int x 5; int* p x; *p 100;这里*p指的是p指向的那个变量。而p指向x所以*p 100;实际上就是x 100;最终x 10015. 图示理解开始p ┌──────┐ │ 1000 │ └──────┘ │ ▼ 地址1000 x ┌──────┐ │ 5 │ └──────┘执行*p 100;意思顺着p找到地址 1000把那个位置的内容改成 100。于是p ┌──────┐ │ 1000 │ └──────┘ │ ▼ x ┌──────┐ │ 100 │ └──────┘16. 完整程序#include iostream int main() { int x 5; int* p x; std::cout x std::endl; std::cout *p std::endl; *p 100; std::cout x std::endl; return 0; }输出5 5 100为什么第一次std::cout x;输出5第二次std::cout *p;因为p指向x所以也是5然后*p 100;直接修改x。最后输出10017. 指针和引用是不是很像非常像。引用int x 5; int ref x; ref 100;结果x 100指针int x 5; int* p x; *p 100;结果同样x 100所以你可能问那为什么还要两种非常好的问题。现在先不深入先建立最简单区别。18. 引用更像“别名”int ref x;可以理解成x 和 ref 是同一个东西的两个名字以后正常使用ref 10;不需要特殊符号。19. 指针更像“地址纸条”int* p x;p自己是一个变量。里面保存x的地址。如果想操作x*p需要先“顺着地址找过去”。所以引用 ≈ 别名 指针 ≈ 保存地址的变量20. 用现实地址类比假设x 一台机械臂引用ref相当于给这台机械臂起了另一个名字。指针p相当于你手里有一张纸“机械臂在 3号实验室”这个纸条不是机械臂本身。它只是告诉你去哪里找到机械臂。然后*p就相当于按纸条上的地址找到机械臂本体。21.int* p里的*和*p又有区别这也是初学者容易混的地方。声明时int* p;这里的*表示p是一个指针变量。使用时*p这里的*表示访问p指向的那个变量。虽然都是*但是所在位置不同。先根据上下文区分。22. 现在把四个东西放在一起int x 5; int* p x;牢记x ↓ 变量的值 5 x ↓ 变量的地址 p ↓ p 保存的地址 也就是 x *p ↓ p 指向地址里的值 也就是 x 也就是 5所以可以记成p x *p x这是非常重要的一组关系。23. 指针怎么用于函数上一课我们用引用void change(int a) { a 100; }指针也能做到。例如void change(int* p) { *p 100; }调用时int x 5; change(x);注意这里不再传x而是传x也就是x的地址。24. 一步一步看函数void change(int* p)表示change需要接收一个int的地址。外面int x 5;然后change(x);把x 的地址传进去。于是函数里的p保存x 的地址再执行*p 100;就是根据地址找到x把它改成 100。所以最终x 10025. 引用参数和指针参数对比引用void change(int a) { a 100; } change(x);指针void change(int* p) { *p 100; } change(x);两者都能修改外部的x。但是写法明显不同。现在先记住结构不需要判断“哪个更好”。后面随着工程代码学习我们会讲使用场景。26. 机器人里为什么会遇到指针非常多。比如以后你处理传感器数据 图像 数组 动态内存 ROS2消息 设备驱动 串口缓存区 CAN数据经常会出现地址。例如你以后可能见uint8_t* data;它大概意思就是data是一个指针指向一块uint8_t数据。或者 OpenCV、底层驱动程序里经常会涉及一块连续内存到底在哪里。所以指针是 C/C 底层编程能力的核心。27. 但为什么指针容易出问题因为指针保存的是地址。如果地址错误找错房间你就可能访问不属于自己的内存。这会导致程序崩溃 数据被破坏 Segmentation fault所以以后我们会专门讲nullptr以及空指针、野指针、悬空指针但今天不要一下塞太多。28. 今天只掌握这一张图int x 5; int* p x;对应p ┌────────┐ │ 地址 │ └───┬────┘ │ ▼ x ┌────────┐ │ 5 │ └────────┘并且x → 5 x → x的地址 p → x的地址 *p → 5如果把这个真正理解指针就迈过第一道坎了。本课小练习第 1 题int x 10; int* p x;那么*p ?第 2 题int x 5; int* p x; *p 20;最后x ?第 3 题用自己的话分别解释x和*p第 4 题下面代码void change(int* p) { *p 50; } int main() { int x 3; change(x); }最后x ?