内存是按字节编号的一栋宿舍楼,地址就是房间号;指针是【存房间号的变量】——它不存住户(数据),存的是【住哪儿】。C/C++ 把裸指针交到你手里:既能直取内存高效干活,也是天下一半安全漏洞的老家。
3-4 说变量是【贴名字的盒子】,这一篇掀开地板:盒子本身也有位置(地址)。回收 C++ 课 7.4 指针与 7.4.2 取地址运算符——那一课学语法,这一课讲【为什么要有这东西】。
一、地址:每个字节都有房号
内存(主存)的最小编址单位是字节——第一个字节编号 0、第二个 1……到几十亿(这就是 32 位机 4GB、64 位机动辄上 TB 的来源:地址总线宽度决定房号能编多大)。
程序里每个变量都住在某几个连续字节里。查住址(Python 用 id() 近似演示,C 用 &):
x = 42
print(id(x)) # 1947962734608(每次运行不同的一串大数字)
那个大数字就是【x 的数据住在内存里的地址】——宿舍楼的真实房号。
二、指针:存地址的变量
普通变量存值;指针变量存地址:
int x = 42; // 普通变量:盒子装值
int* p = &x; // 指针:p 装的是 x 的地址(& 是取地址符)
printf("%d\n", *p); // 42 —— * 是解引用:顺着房号找上门取值
*p = 99; // 顺房号上门【改】值 -> x 变成 99
两个专用符号各管一件事:& 取地址(问【住在哪】)、* 解引用(顺着地址【找上门】)。指针的两大用途:
- 函数要改外面的变量——传值是复印一份改(原件不动),传指针是【把真房号给函数】(能上门改原件);
- 大对象不搬家——传 1GB 的数组【复印件】要 1GB 的时间;传指针只传 8 字节的房号。
三、裸指针:权力越大,事故越狠
C/C++ 的指针是裸指针——房号可以乱写、门可以乱闯:
- 野指针:存了个没分配的房号(房子拆了/根本没盖)就解引用——程序当场崩溃;
- 越界:顺着指针走过头,读到/改到别人家(3-8 的数组越界就是这类)——内存安全漏洞(缓冲区溢出攻击)的祖师爷;
- 内存泄漏:C 里动态要的房子(malloc)用完不还(free),房子越占越多直到系统卡死。
于是有两条后继路线:C++ 用智能指针自动还房;Python/Java 干脆不给你裸指针——变量持的是【受管理的引用】,分配与回收(垃圾回收)全由运行时代办。你在这两门语言里没摸过指针,但 id() 的地址、对象引用、None(空引用,对应 C 的 NULL)全是同一族概念的安全版。
四、动手 Demo:查住址与共享盒子
a = [1, 2, 3] # 列表对象:房子
b = a # 把【房号】抄给 b —— 不复印房子!
print(id(a) == id(b)) # True:两个名字同一间房
b.append(4)
print(a) # [1, 2, 3, 4] —— 顺着 b 改,a 看得见
看到什么算成功:True 和 [1, 2, 3, 4]。
读结果:b = a 拷贝的是地址(引用)不是内容——两个名字指同一间房,所以 b 加的 4 在 a 里也看得见。这就是【传指针】的效应在 Python 里的样子;要真复印得显式调 a.copy()(回收树莓派课 6-6 的原地方法返回 None 那一族坑)。
五、30 秒实验
跑 a = [1]; b = a; b = [9]; print(a)——输出 [1]。b 被重新赋值是【换了房号】(b 不再指原来的房),不是【改原房】;和上一个 Demo 的 b.append 对比——改房子 vs 换房号,一字之差天壤之别。
六、常见误区
- 【指针和普通变量是两种世界的概念】——错。指针就是【以地址为值】的普通变量;它的类型只说明【这房里住的是什么类型】,解引用时按那个类型解读。
- 【Python/Java 没有指针,所以那套知识用不上】——错。引用就是受管的指针:id() 是地址、共享对象是【传引用】、None 是 NULL——只是【乱闯】的权力被收走了。懂指针才懂【为什么 b = a 之后改 b 会影响 a】。
- 【NULL 是 0 号房间】——不严谨。NULL/None 表示【不指向任何房】;解引用空指针(C 里
*p当 p 为 NULL)是必崩的经典事故——【先判空再解引用】是铁纪律。
自测三问(点开对答案)
1. **取地址符与解引用符各干什么?** 答:& 问【住哪儿】(拿到地址);* 顺着地址【找上门】(读写那个位置的值)——一去一回。 2. **为什么大对象传参用指针/引用?** 答:传指针只复制 8 字节房号;传值要整体复印(1GB 就搬 1GB)——快慢相差万倍。 3. **野指针和内存泄漏分别是什么?** 答:野指针=存着无效地址就去解引用(当场崩);泄漏=动态要的内存不归还(房子越占越多直至卡死)——一个炸得快,一个耗得久。- ☐ 下一节(3-15 链表、双向列表、环形列表)
相关笔记
- 变量、常量 —— 盒子论的地板下面
- C++ 7.4 · 指针 —— C 语言的裸指针语法
- 树莓派 6-6 · Python 列表与字符串 —— 引用行为的第一次遭遇
- ⌨️ 编程原理 · 索引 —— 全课路线图