指针就是装地址的变量:普通变量装数据,指针变量装【数据在哪儿】;解引用,就是拿着门牌号去找人。
4.2 讲的是【怎么理解地址】,这一节讲【把地址当成数据来用】。
一、普通变量和指针变量的区别
普通变量里装的是数据本身:n = 42,格子 100 号里就写着 42。
指针变量里装的是地址:p 自己的格子(104 号)里写着 100——也就是 n 在哪儿。
一句话:指针不是什么高级东西,它只是一个值恰好是地址的普通变量。
所以指针能参与运算、能比较大小、能放进数组——跟别的变量没有两样。
二、两个动作:取地址与解引用
教材用 C 语言演示,只有两个符号要记:
&a 是取地址——问出 a 住在哪儿。
*p 是解引用——顺着 p 里记的地址,去把那格的数据取出来。
于是 p = &a; 之后,*p 和 a 指的是同一个格子——改哪个都算改它。
三、为什么非要用它
一、让函数改得动外面的变量。 C 语言的参数是按值传的,直接把变量传进去改不了;传地址就行。 二、处理大小不定的数据。 与其把一大块数据搬来搬去,不如只传它开头的地址。 三、把数据串起来。 链表、树、图全靠【存着下一个的地址】才连得起来——那是 4.6、4.7 的主角。 所以指针不是炫技,它是唯一能让程序【指来指去】的工具。
四、Python 里没有指针,但有引用
Python 把指针藏起来了,你看到的是引用:变量指向某个对象,赋值只是让两个名字指向同一份数据。
b = a 之后改 b,a 也跟着变——因为本来就是同一份。
c = a[:] 是新复制的一份,改它就不影响 a。
所以【浅拷贝还是深拷贝】【函数里改了列表外面为什么也变了】这类问题,根子都在这一节。
五、动手 Demo:指针其实很简单
普通变量装数据,指针变量装地址——就这么点差别。 Python 没有指针语法,但引用就是它的影子。
a = [1, 2, 3]
b = a # b 和 a 指的是同一份数据
c = a[:] # c 是新复制的一份
b.append(4)
print("a =", a)
print("b =", b)
print("c =", c)
实跑输出:
--------------------------------------------------------------------
指针其实很简单
--------------------------------------------------------------------
**指针就是【装地址的变量】。** 普通变量装数据,指针变量装地址。
把内存画成一张表看看(地址是模拟的,只为对照):
变量 它占的地址 里面装的是什么
----------------------------------------------------
n 100 数据 42
p 104 地址 100(也就是 n 在哪儿)
读 p 得到 100,再拿 100 去内存里找——就取到了 42。
**所谓【解引用】,就是这么一回找门牌号的事。**
Python 里没有指针这个语法,但**引用就是它的影子**:
a = [1, 2, 3]
b = a # b 和 a 指的是同一份数据
c = a[:] # c 是新复制的一份
b.append(4)
a = [1, 2, 3, 4] b = [1, 2, 3, 4] c = [1, 2, 3]
**改 b 会连 a 一起动,改 c 不会——差别就在【是不是同一份】。**
那些【浅拷贝还是深拷贝】的问题,根子都在这儿。
改 b 连 a 一起动,改 c 不影响 a——差别就在是不是同一份。 回头把指针的几个麻烦(野指针、内存泄漏)也理解成【地址指错了地方】,就不难了。
30 秒实验
- 写一个函数,接收列表并往里加一个元素,看看外面的列表变不变。
- 把列表换成整数再试一次,对比结果——这就是【传值】和【传地址】的差别。
常见误区
- 以为指针是高级特性。它只是个装地址的普通变量。
- 把
&和*记反。&a取地址,*p顺着地址取数据。
自测三问(点开对答案)
1. 指针变量里装的是什么? —— 另一个变量(或数据)的地址。 2. 取地址和解引用分别怎么写? —— `&a` 取 a 的地址;`*p` 顺着 p 里的地址把数据取出来。 3. Python 的引用和指针是什么关系? —— Python 把指针藏起来了,引用就是它的表现——两个名字可以指向同一份数据。- ☐ 下一节(4.4 用好内存先从数组开始)
相关笔记
- 内存的逻辑结构像一幢大楼 — 地址的换算尺子
- 在链表中添加和删除元素很容易 — 指针最出彩的地方
- 用基址和变址实现数组 — CPU 侧的对应做法
- 🔷 C++基础 · 索引 — 指针讲得最细的一门课
- ⚙️ 程序是怎样跑起来的 · 索引