如果数学是科学的皇冠,那么指针就是C语言的皇冠。指针在底层系统语言作用卓越,语言越高级越会远离指针,毕竟指针出错可能万劫不复,程序员再小心毕竟也是人。
计算机硬件和指针
- 计算机硬件中,PC/EBP/ESP等寄存器的使用就是指针的原型,C/C++用*指代。
- 汇编指令lea对应获取变量的地址,intel汇编中括号[addr] 对应*addr.
- 计算机硬件表达指针也有不同形态,有使用段+偏移,也有直接使用偏移(比如32位扁平地址),就有了near/far指针。
为什么还要研究数据的地址?
- 指针说白了,就是数据的地址,在这个大数据时代,我们关注的不应该是数据的内容吗?地址是什么?换个角度,没有地址,怎么会有数据。ChatGPT找不到数据的位置,怎么建立大数据?
- 数据的地址用于研究如何访问数据,操作系统最大的目标是尽可能精准的访问到所有该访问的内存,它并不关注数据内容,数据在哪里以及更快的访问到是它最重要的技术目标。
- Java申请对象,使用它似乎没用到它的地址,事实上,编译器已经提前把地址信息准备好了,不显式给程序员。
- 大国海战首先在意的是本国航母的地址,被提前发现就可能提前被毁灭丧失主动权。
高级语言的"指针"
- 不要以为高级语言没有明确的指针概念,就代表没有指针。任何高级语言能够正确执行,必须隐式支持”指针”,可以让编译器或解释器支援,不让程序员有明显的感觉。
- 一个最简单的例子,申请了一段内存,另外一个函数需要修改此内存第100字节的内容,没有指针,是不可能实现。
- C++引入“引用”, 是指针的别名,减少复杂的指针操作带来意外的可能。
- 这是一个非常简单的技术,其实本质是因为编译器知道变量或者对象在何时被操作,只要试图从程序员角度思考,不让程序员写出指针,编译器”偷偷加上指针”。
- Java/C#默认所有对象类型都是引用类型(类似于C++对象指针)。
- C#引入ref关键字以和值传递区分。
数组和指针
- 数组变量做参数,被看做指针。下图,函数f的参数arr是高亮位置,对应a的地址值。
int f(int arr[])
{
int a = arr[0];
return a;
}
int a[3] = {1, 2, 3};
f(a);

指针的格式
- %p是标准做法,也可以用%x.
指针和数组的效率
- 可能有人会说指针效率更高,源于早期PDP-11用指针效率更高。事实上,现代编译器有不少优化技术,取决于编译器。
- 现代编译器可以正确识别数组和指针,好的编译器会用最高效的方式。比如,如果是连续地址赋值会优化成rep movs指令。
指针运算
- 不像基本数据类型那样加减乘除都可以,指针提供和数字的加、减以及指针之间相减运算,这是为了方便指针跳动以及判断指针相对位置。
- 指针显然不能和其他指针相乘或相除,也不能和数字做乘法和除法,因为不能确定结果对应的内存区域和原始指针是否同属一个”功能区”。