☰
C++ 第 15 课:指针 * 和地址
2026/10/2 6:54:19 网站建设 项目流程

上一课标准答案:

  1. 最终输出:
20

因为:

void change(int& a)

中的a是x的引用,修改a就是在修改原来的x。

    x = 30 y = 30

    因为:

    int& y = x;

    表示y是x的别名,它们对应同一个变量。

    1. 本质区别:
    void test(int a)

    是值传递:

    把原变量的值复制一份给a,修改a不影响原变量。

    而:

    void test(int& a)

    是引用传递:

    a直接引用原变量,修改a会修改原变量。

    1. 最后:
    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 = ?

    需要专业的网站建设服务?

    联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

    立即咨询