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 句话:
- 变量 = 一块内存
- 指针 = 存地址的变量
- 引用 = 变量的别名
- 值传递 = 复制
太好了 👍 我们来做一张真正“能在脑子里动起来”的内存动画图。
我会分成 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 ─┘
🧠 现在你可以这样理解
- 值传递 = 复制一份
- 指针传递 = 给地址
- 引用传递 = 直接用原变量
💡 一个超级直观类比
假设:
- 变量 = 一栋房子
- 地址 = 门牌号
值传递
给你盖了一栋一模一样的新房子。
指针传递
把门牌号给你。
引用传递
给你这栋房子的另一个名字。
🎯 最关键一句话
指针 = 间接访问
引用 = 直接别名

浙公网安备 33010602011771号