C++的 & 、*

太好了 👍
你现在这个“似懂非懂”的阶段,其实是最关键的阶段

C++ 这里确实会让人混乱,因为:

*     有 3 种用法
&     有 2 种用法

我们今天彻底帮你理清楚,而且只讲最本质的,不绕。


一、先建立一个核心概念(非常重要)

在 C++ 里:

变量本质上就是一块内存

比如:

int a = 10;

内存里是这样:

地址 1000 → 10

a 只是 1000 这个地址的名字。


二、什么是指针(*)

1️⃣ 指针是“存地址的变量”

int a = 10;
int* p = &a;

现在内存是:

地址 1000 → 10      (a)
地址 2000 → 1000    (p)
  • &a = 取地址
  • p = 存地址
  • *p = 访问那个地址里的值

2️⃣ * 有两种含义

① 定义指针

int* p;

这里的 * 表示:

p 是指针


② 解引用

*p = 20;

这里的 * 表示:

访问指针指向的内容


三、什么是 &

1️⃣ 取地址

int a = 10;
int* p = &a;

这里的 & 是:

取 a 的地址


2️⃣ 定义引用

int& r = a;

这里的 & 是:

r 是 a 的别名

此时:

r 和 a 是同一个东西

不是复制,不是新变量。


四、值传递

void func(int x)
{
    x = 100;
}

int main()
{
    int a = 10;
    func(a);
}

发生了:

复制 a 给 x
x = 100
a 不变

这叫:

值传递(copy)


五、指针传递(地址传递)

void func(int* p)
{
    *p = 100;
}

int main()
{
    int a = 10;
    func(&a);
}

发生了:

传入 a 的地址
通过 *p 修改 a

a 会变成 100。


六、引用传递

void func(int& r)
{
    r = 100;
}

int main()
{
    int a = 10;
    func(a);
}

这里:

r 就是 a

所以 a 变成 100。


七、三种传递方式对比(核心表)

方式 写法 是否复制 是否能改原变量
值传递 int x
指针传递 int* p
引用传递 int& r

八、指针 vs 引用(真正区别)

指针 引用
可以为空
可以改指向
需要解引用
更安全

九、为什么 C++ 既要指针又要引用?

因为:

指针更灵活

  • 可以 nullptr
  • 可以改指向
  • 可以做数组
  • 可以做动态内存

引用更安全

  • 不用担心 nullptr
  • 语法简单
  • 常用于函数参数

十、给你一个终极理解公式

记住这个就够了:

*  是“通过地址找值”
&  是“要地址”或者“别名”

十一、你现在混乱的根源

其实是因为:

C++ 把“内存”直接暴露给你
C# 把“内存”帮你隐藏了

你现在是在接触“更底层”的世界。

这不是你笨,这是你在升级。


十二、我帮你做一个超级简化总结

只记住这 4 句话:

  1. 变量 = 一块内存
  2. 指针 = 存地址的变量
  3. 引用 = 变量的别名
  4. 值传递 = 复制


太好了 👍 我们来做一张真正“能在脑子里动起来”的内存动画图。

我会分成 3 个场景:

1️⃣ 普通变量
2️⃣ 指针
3️⃣ 引用
4️⃣ 三种函数传参对比

你跟着一步一步看。


🎬 场景一:普通变量

int a = 10;

假设内存是这样:

地址        内容
0x1000      10
a ───────► 0x1000

👉 a 只是 0x1000 这块内存的“名字”


🎬 场景二:指针

int a = 10;
int* p = &a;

现在内存变成:

地址        内容
0x1000      10        (a)
0x2000      0x1000    (p)

动画理解:

a ───────► 0x1000 : 10

p ───────► 0x2000 : 0x1000
                         │
                         ▼
                    0x1000 : 10

关键理解:

  • p 存的是地址
  • *p 才是 10

如果:

*p = 99;

动画变成:

0x1000 : 99

a 也变成 99。


🎬 场景三:引用

int a = 10;
int& r = a;

注意:

引用 不会新开一块内存

内存还是:

地址        内容
0x1000      10

但是现在:

a ─┐
   ├──────► 0x1000 : 10
r ─┘

👉 r 和 a 指向同一块内存
👉 r 就是 a 的“另一个名字”

如果:

r = 50;

结果:

0x1000 : 50

a 也变成 50。


🎬 场景四:值传递(函数)

void func(int x)
{
    x = 100;
}

int main()
{
    int a = 10;
    func(a);
}

动画过程:

调用前

0x1000 : 10   (a)

调用时(复制)

0x1000 : 10   (a)
0x3000 : 10   (x)

修改 x:

0x3000 : 100

函数结束:

0x3000 被销毁

最终:

a 仍然是 10

🎬 场景五:指针传递

void func(int* p)
{
    *p = 100;
}

int main()
{
    int a = 10;
    func(&a);
}

调用时:

0x1000 : 10   (a)
0x3000 : 0x1000   (p)

执行:

*p = 100;

变成:

0x1000 : 100

a 被修改。


🎬 场景六:引用传递

void func(int& r)
{
    r = 100;
}

调用时:

a ─┐
   ├──► 0x1000 : 10
r ─┘

执行:

0x1000 : 100

a 变成 100。

没有新内存。


🔥 终极动态对比图

值传递

a  ───► [10]
x  ───► [10]   (新拷贝)

指针传递

a  ───► [10]
p  ───► (地址) ───► [10]

引用传递

a  ─┐
   ├──► [10]
r  ─┘

🧠 现在你可以这样理解

  • 值传递 = 复制一份
  • 指针传递 = 给地址
  • 引用传递 = 直接用原变量

💡 一个超级直观类比

假设:

  • 变量 = 一栋房子
  • 地址 = 门牌号

值传递

给你盖了一栋一模一样的新房子。

指针传递

把门牌号给你。

引用传递

给你这栋房子的另一个名字。


🎯 最关键一句话

指针 = 间接访问
引用 = 直接别名

posted @ 2026-02-24 12:00  长松入霄汉远望不盈尺  阅读(2)  评论(0)    收藏  举报