cnyinlinux
指针,被称做C语言编程的精华。其闻名数十年的秘诀在于,高效二字。今天我们讲的就是,指针是如何做到了这一切的。
经常你会看到这样的形式:
XXX * func(int para1,…);//函数参数略
函数的返回值类型为指针,为何要返回一个指针呢?
指针在C中代表的是一片内存,也就意味着该函数返回时,将一片内存带给了原调函数(调用该函数的函数称为原调函数)。这样做的目的是将函数处理结果存于内存,直接把存储地址返回。这样原调函数在获取结果的时候不必要再复制数据,直接在返回指针指向的内存中去操作。
还有时候你会见到下述样子的函数:
XXX func(const char * src, char * dest);
这个函数的入参变成了指针,这样又有什么好处呢?首先,如果该函数如果是处理大片数据的话,原调函数直接将数据的内存地址传递给被调用函数,避免了繁琐的内存复制工作。其次,如果处理的结果也是直接放在传入的指针指向的内存区,被调函数返回时无需再复制结果给原调函数。
从上面两个例子可以看出,指针的作用就是避免了数据的冗余复制操作,也就是繁重的搬运工作。这就是指针高效的原因。简而言之,指针技术采用直接传递地址的方式,避免多余的数据复制,节省了处理时间,同时节省了额外开辟内存的资源消耗,因此使得程序高效性得到了保障。
下面我们再来看看指针的应用。
一,数组。
最为常见的复合数据结构就是数组了,而数组首地址就是自己这片内存区的指针,因此在处理数组的函数中,通常是将数组的首地址传递过去,这样被调函数直接获得原内存区的访问权。同时,在访问每个数组成员的时候,只需要在首地址基础上加上偏移量就得到了。这样使得各成员访问的时间在常数级就可完成。
二,地址传递。
其实,除了数组,一般我们在处理很多基本数据类型的时候也可以采用指针。
如要在被调函数返回多个基本数据类型的变量的值,通过函数return难以实现,这个时候额可以考虑传递指针的方式,直接在被调函数内部将数值放置在传入指针指示的位置处。这样不光避免了return的局限性,还避免了原调函数的复制操作,近一步简化了函数调用的代码逻辑。
三,数组指针。
说到数组指针,很容易联系到二维数组。的确,二者很相似,可以这么理解,二维数组的第1维度是个数组指针,而第2维度是普通数组,这样第1维度每移动1个步长,其指向的内存区就移动了一个1维数组的长度。其实,数组指针就是一种代表着数组为指类的指针。
也就是说这个指针所代表的内存区指的是它的值开始的一个数组大小的区域。这样它其实就被上升到了与二重指针同等的级别上了。也就是说,数组指针也是一种特殊的二重指针,但是它不能通过简单的两次脱指(**)操作来完成内容的访问,因为它代表的是一片内存,所以需要用到类似数组的偏移方法去访问每一个成员。
如 int (*pa)[10];,pa代表的是10个int的内存去,当你要访问pa的第一个成员的时候(下标从0开始)的话,它应该写为 *((int *)pa + 1) 而绝不是pa[1]。
四,函数指针。
顾名思义,就是指向函数的指针叫做函数指针。函数指针的功能是指向一片可执行的代码段地址,这样可以在某个子函数内部需要执行其他函数的时候,可以通过传递函数指针的方式告知该子函数要执行的代码片段。在软件模块化设计研究中,函数指针也有广泛的应用,比如分离多模块之间的功能调用衔接,可以采用指针池的方式实现多个子系统之间的处理调用关系。通过指针调用的函数称之为回调函数,用在系统的信号处理,应用软件的事件触发方面等较为常见。
五,多重指针。
指针作为一个存放内存地址的变量,存储的是一个有效的内存地址的值。所以它的大小就该满足系统的寻址规则,32位系统上为4字节,64位系统上为8字节。指针无论有多少重,它的本质不会变化,都是存储一个内存地址值,只是它存储的那个地址代表的含义是另一个指针还是存储最终数据的内存地址不同而已。多重指针无非是指向关系多了几层,他们的处理方式是不变的。所以,多重指针用到第3重就可以了,重数再高就意义不大了。多重指针就像个手表,不同的层级代表不同的含义,最终合起来表示一个完整含义。
六,指针数组。
如其名,它就是个数组,只不过成员是指针而已。可以是基本数据类型,也可以是复合类型指针,还可以是函数指针。具体每个成员指针的特性与上面讲述的吻合。
<<<本文完结>>>