Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

引用与指针

复习

  • 数组:连续存储,按下标随机访问
  • 抽象数据类型:接口与实现分离
  • 程序在内存里的样子:代码、数据、栈和堆

TL;DR

  • 指针/引用保存的不是数据本身,而是数据所在的位置
  • 通过它,可以在别处访问同一块数据
  • 悬空引用指向已被释放的空间,非常危险
  • 有了指针,数据就不必再连续存放

正文

  数组靠“连续”换来了随机访问。可现实中的很多数据,天生就是零散的,硬要挤在一起既不方便,也做不到。要想把它们串起来,就需要一样新工具:指针

保存“位置”,而不是“内容”

  指针(pointer)保存的,不是数据本身,而是数据所在的地址

  它和“引用”(reference)是近亲:引用通常是指针的一层友好封装,用起来更像是“数据的别名”。

  打个比方:房间号不是房间本身,但它能带你找到那个房间;书签不是书,但它指出了你读到哪一页。指针就是内存世界的“房间号”或“书签”。通过它,你能在程序的一个地方,访问到存放在另一个地方的数据。

有了它,数据不必连续

  指针最深远的贡献,是解除了“连续性”的束缚

  数据可以零零散散地放在内存各处,只要每个数据里保存着“下一个数据在哪里”,就能把它们连成一串。这样一来:

  • 插入、删除不必再像数组那样整体挪动,只要改几个指针即可
  • 数据不必挤在一段连续空间里,更容易动态分配

  这为下一章的链表铺平了道路:链表正是靠指针,把分散的节点连了起来。

强大,也危险

  指针给了程序很大的自由,也带来了著名的麻烦:

  • 空指针:指向“什么都没有”,一旦使用就会出错
  • 悬空指针:指向的内存已经被释放,可指针还留着,再去访问就访问到垃圾或别人的数据
  • 越界/野指针:指到了不该指的地方

  其中悬空指针尤其阴险:它平时可能“看起来正常”,直到某天才突然出错,而且很难复现。自由越大,责任越大——这也是一些新语言选择把指针“藏起来”、只提供安全引用的原因。

  理解了指针,就可以看看用它在数据之间“牵线搭桥”的第一个结构了。

思考题 1

  指针保存的是数据本身,还是数据的位置?这带来了什么灵活性?

思考题 2

  悬空指针为什么危险,而且往往很难排查?

小结

知识点

  • 指针/引用保存数据的位置而非内容
  • 通过指针可在别处访问同一块数据
  • 指针让数据不必连续存放
  • 空指针、悬空指针、越界指针都很危险

参考资料

  1. Wikipedia(zh):指针 (计算机科学):保存内存地址的变量
  2. Wikipedia(zh):悬空指针:指向已释放内存的指针

思考题答案(仅供参考)

思考题 1

  保存的是数据的位置(地址)。这样的好处是:数据本身可以放在任意地方,程序只要拿到地址就能在别处访问它;数据也不必连续存放,插入删除可以通过改指针完成,而不必整体挪动。

思考题 2

  因为它指向的内存可能已经被释放或改作他用,再去访问就会读到垃圾或被别人改过的数据,导致难以预料的行为。更麻烦的是,它可能平时不出错、只在特定时机暴露,很难稳定复现,因此排查困难。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪