上一课标准答案:
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
房间内容:5
4. 怎么知道 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;
输出:
5
13. 现在我们有三个不同的东西
假设:
int x = 5;
int* p = &x;
那么:
x
表示:
x 里面的值
也就是:
5
&x
表示:
x 的地址
例如假设:
1000
p
表示:
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 = 100
15. 图示理解
开始:
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。
最后输出:
100
17. 指针和引用是不是很像?
非常像。
引用:
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 = 100
25. 引用参数和指针参数对比
引用
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 = ?
网硕互联帮助中心![C++入门篇(十):string(上)——认识string:构造与三大遍历(一条龙讲透operator[]、迭代器、auto、范围for)-网硕互联帮助中心](https://www.wsisp.com/helps/wp-content/uploads/2026/10/20261001032318-6abdd226d398f.png)




评论前必须登录!
注册