在计算机科学中,指针(英语:Pointer),是编程语言中的一类数据类型及其对象或变量,用来表示或存储一个存储器地址,这个地址的值直接指向(points to)存在该地址的对象的值。
指针参考(reference)了存储器中一个地址。通过被称为指针反参考(dereferencing)的动作,可以取出在那个地址中存储的值。保存在指针指向的地址中的值,可能代表另一个变量、结构、对象或函数。但是从指针值是无法得知它所引用的存储器中存储了什么数据类型的信息。可以打个比方,假设将电脑存储器当成一本书,一张内容记录了某个页码加上行号的便利贴,可以被当成是一个指向特定页面的指针;根据便利粘贴面的页码与行号,翻到那个页面,把那个页面的那一行文字读出来,就相当于是对这个指针进行反参考的动作。可做一类比以增强对指针的理解:整型(integral)也是一类数据类型及其对象或变量,可定义具体的数据类型如短整型(short)、长整型(long)、超长整型(long long)、无符号整型(unsigned)等等;也可以用于称呼整型值、整型对象、整型变量等。又如,一个浮点指针(float *),可称作指向了一个浮点类型的对象。
在高级语言中,指针有效的取代了在低级语言(如汇编语言与机器代码)直接使用内存地址。但它可能只适用于合法地址之中。因为指针更贴近硬件,编译器能够很容易的将指针翻译为机器代码,这使指针操作时的负担较少,因此能够提高程序的运作速度。
使用指针能够简化许多数据结构的实现,例如在遍历字符串,查取表格,控制表格及树状结构上。对指针进行复制,之后再解引用指针以取出数据,无论在时间或空间上,都比直接复制及访问数据本身来的经济快速。指针表示法较为直觉,使程序的表达更为简洁,同时也能够提供动态机制来创建新的节点。
在程序编程(procedural programming)中,指针也被用来保存系统调用流程,以及动态链接数据库(DLL)的进入点地址。在面向对象编程中,使用函数指针(Function pointer)来绑定方法(method),常见于虚拟方法表(Virtual method table)中。
但是指针本身也存在一些可被滥用之处,在访问某个数据结构时,可能会超出可用范围,使软件或操作系统出现异常,严重时可造成死机。利用指针去访问或修改非合法可取用的数据,也可能造成安全性问题。为此,C与C++语言规定指针类型为强类型,即指针值不仅是一个内存地址,同时它的数据类型说明了存在这个地址可以安全访问的地址的范围,例如,float*可以访问4个字节的内存空间,double*可以访问8个字节的内存空间。
许多编程语言中都支持某种形式的指针,最著名的是C语言,但是有些编程语言对指针的运用采取比较严格的限制。因为指针的机制比较简单,其功能可以被集中重新实现成更抽象化的引用(reference)数据形别,如Java一般避免用指针,改为使用引用。
在1964年,哈罗德·劳森发明了最早的指针。他在PL/I中实现出了这个概念,其他高级编程语言也很快跟进,使用了这个想法。指针(pointer)这个名称首次出现在系统发展公司(System Development Corporation,SDC)的技术文件,当中使用了堆栈指针(stack pointer)这个名词。
在计算机科学中,指针是一种最简单形式的引用(reference)。
指针有两种含义,一是作为数据类型,二是作为实体。前者如字符指针、浮点指针等等;后者如指针对象、指针变量等。
指针作为数据类型,可以从一个函数类型、一个对象类型或者一个不完备类型中导出。从中导出的数据类型称之为被引用类型(referenced type)。指针类型描述了一类的对象,对象值为对被引用类型的实体的引用。
C++标准中规定,“指针”概念不适用于成员指针(不包含指向静态成员的指针)。C++标准规定,指针分为两类:
C99与C++11标准分别明确规定了把一个指针值转换自(from)/成(to)整形是允许的,但整型的大小至少不低于std::intptr_t
。
在C语言的多数实现中,指针值是一个以当前系统寻址范围为取值范围的整数。
32位系统的寻址能力(地址空间)是4GB(0~232-1),以二进制表示时长度为32比特,每格存储空间是1 Byte。不难验证,在32位系统的大多数实现里,int
类型也正好是32-bit长度,可以取遍上述范围。
同理,64位系统取值范围为0~264-1,int
类型长度为64-bit。
如果没有指针,很难用一个统一的模式去A
的定位并修改一棵树的结点。例如:不用指针要修改A
的左子树的左子树的右子结点,只有“A.LC.LC.RC=…
”一种表达方式,不能通过赋值而简化。
C中函数调用是按值传递的,传入参数在子函数中只是一个初值相等的副本,无法对传入参数作任何改动。但实际编程中,经常要改动传入参数的值。在C语言中一般通过传入参数的地址而不是原参数本身来实现。当对传入参数(地址)取“*
”运算时,就可以直接在内存中修改,从而改动原想作为传入参数的参数值。
#include <stdio.h>void inc(int *val){ (*val)++;}int main(){ int a=3; inc(&a); printf("%d\n", a); return 0;}// Output:// 4