大科学家阿基米德曾说给他一根杠杆,就可以撬动整个地球,只要这根杠杆够长,够结实。同样,C语言编程时,掌握一个起始指针,加上合适的数据结构,就可以串起程序所需的所有数据。使用时只要拿到这根数据链的手柄(即起始指针),就能遍历访问链上的所有信息,这是指针的另一个作用:数据连接。在这种应用场合指针近似另一个概念--"句柄"。
英文"Handle"在计算机软件中译为"句柄"。广义上,如果能通过一个值顺藤摸瓜地遍历访问一串数据,这个起始值就可以叫句柄。这里尝试区分指针和狭义句柄。句柄这个词主要用于操作系统。比如Windows 包含许多内核对象:打开的文件,创建的线程,程序窗口等,这些对象有很多属性,系统用内存块保存它们,那怎样在程序间或程序内部函数间传递这些数据呢?拷贝的效率太低,直接传递这些属性块的地址是一个办法,但有两个缺点:
1)暴露内核对象,使用户程序(而不是系统内核)能随意修改内核对象的内部状态(地址都知道了,还有什么不能改?),这违背现代操作系统隔离用户,保护内核的宗旨。
2)桌面操作系统定期整理内存,如果整理过后,上述对象被移到别的地址怎么办?于是操作系统新建中间层:系统在每个进程的地址空间中维护一张表,表里保存着一些编号和与其一一对应的地址(如编号1对应地址0x123456......),这些地址指向实际的内核对象,而编号与对应的地址没有规律性的联系。OS整理内存并移动内核对象时,只要正确更新这张表就能继续通过编号找到对象地址。而这些能够映射到对象地址的编号就是所谓的“句柄”。
可见,虽然不是直接用指针作为"句柄",但指针是句柄的基础,句柄只是系统在用户访问接口和各种内核对象指针之间建立的中间转换层。用户程序访问系统对象属性主要还是利用指针的功能,通过首指针和约定的结构按图索骥访问数据。
指针这种“聚拢”信息到一点的能力在编程中经常被采用,比如我们熟悉的文件操作,所有接口都基于一个“文件指针”(也有人称文件句柄,或许只要是信息集合的入口都可称为句柄)。如:FILE *fp = fopen(xxx, xxx); fwrite(fp, xxx); fread(fp, xxx); fclose(fp);这个文件句柄经过系统的检查与转换,就能在内核中找到一个起始指针,它指向一个包含文件所有属性的信息链,通过它可以“顺藤摸瓜”访问链上所有信息(如文件可读写属性,用于fseek操作的文件当前位置等),直至最终找到磁盘上的实际存储数据。
类似功能在第三方模块中也很常见:先调初始化函数,如xxx_init()或xxx_open(),返回handle(多是void*型指针),这个指针在内部指向某结构体,结构体中直接包含或间接连接程序相关数据,后续函数都要把这个handle作为参数,以通过它,找到信息链上的相关数据,退出时调用xxx_free(handle)或xxx_delete(handle)释放这个结构体所占内存。
数据结构中的链表,队列,图等等在C语言中的实现都是通过指针连接复杂的多层结构体来实现。结构体和指针就象火车的车厢和挂钩,可以组合成不同的拓扑连接。但无论哪种数据结构,只要掌握代表车头的指针(handle),就能遍历到所有信息。