6.指针

指针实际上同前面所述的基本数据类型是一样的。它不是构造型数据类型,在前面章节里将指针单独提出来作为一个数据类型,实际上,如果我们这样想,在内存中存储一些数据,这些数据从二进制来说都是01,是没有任何类型之分的,只有当你结合现实的一定意义之后才有相应的数据类型。从汇编的角度,我们知道内存是按线性顺序进行编址的,计算机的数据总线或者地址总线根据线性地址确定内存的空间。这是确定的,唯一的。也就是说内存的编址是确定的,那么换句话,如果某个地址存储一个内存地址值,因此,那么为什么单独列出一个指针类型,而不直接说明它是一个INT类型呢?我想C语言的作者可能是为了更好的区分这种类型,并利用这种类型的一些额外特性进行操作。

C语言基本概念(3)_休闲

如上图所示,上图来源于一个PPT,实际上也并没有表达清楚指针的基本概念,其实如果最简单的就把它当作一个普通的变量,只不过它的值是内存地址。这里有些人经常混淆的是指针变量声明*P和取地址操作&a及P这几个符合的关系。实际上我们前面已经学过变量与运简符之间的关系。变量就是A,B等。只是例外的对指针变量声明时前面加上*,但是*和&同时也是运算操作符,比喻说P是一个地址,*P实际上就是取P地址对应的内存实际的值。 A是一个变量,&A就是取变量A的值。实际上我们可以像数组一样理解指针,比喻说声明一个数组是int a[],声明一个指针变量是int *b;声明之后a就是数组, b就是指针。但是因为数组的取值操作是a[1],而指针的取值操作是*b,就非常不好像看。初学者对这个符号就老是弄不灵清。如果我是C语言的编委,我就改变指针的声明方式,如int <b>表示指针。或者int (b)方式,这样更容易理解指针的概念。有些书上也将指针与指针变量进行区分开来。指针专指地址,指针变量是变量。讲到这里,我就把后面要说的数组与指针变量相互指向提前说明一下,我们前面说到一个数组是数据的有序集合,在内存中是按顺序存储的。其中a就代表了首地址。也就是可以使用a来进行指针操作。

C语言基本概念(3)_C语言_02 C语言基本概念(3)_C语言_03

如上图所示,定义一个指针变量int * i_pointer;  内存给变量i_pointer分配一个实际内存地址3010,并且内部存储一个地址2000.如果 *i_pointer就是取2000地址对应的值。从前面基本类型的内存存储,我们知道不同的类型的变量是分配不同的空间大小。那么指针变量,按理说只是存储内存地址,应该没有类型的,但实际上我们知道,因为指针作为一个内存地址,在真实内存中也会对应到前面定义的基本类型,如果说我们对指针变量不指定类型,那么我们也无法利用这个指针变量与基本数据类型进行相互操作,没有类型,我们无法分配相应的空间去进行等价操作。因此,i_pointer+1对应的内存地址实际上也是加了四个字节。

C语言基本概念(3)_内存_04 C语言基本概念(3)_内存_05

上图是指针变量的简单例子。从这个例子我们引申出一个问题,那就是*pointer_1究竟是变量a还是变量a的值。如果说*pointer_1等价于100,那么&*pointer_1就没有意义了,因此*pointer_1实际上等价的是a,&*point_1就是&a,而*&a就是a。另外(*pointer_1)++就量a++如下图所示:

C语言基本概念(3)_C语言_06

从前面我们知道,C语言中对变量都是传值传递。另外从前面我们也了解到数组的特殊性,数组的首地址可用指针变量表示,因此在传递过程中,指针变量与数组首地址实际上是等价的,如数组a[10],*p;可以直接表示如下p=a.这里a++就表示a[1]的地址。*(a++)就是a[1]的值。这里还有一上需要注意的就是p是变量,从地址值上p=a,但是p++这个操作和a++不是完全等价。

C语言基本概念(3)_C语言_07

对多维数组来说,就比较复杂一点,如二维数组int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};如果首地址为2000,按前面数组章节,我们知道内存是线性存储,将二维数组按行逐列存储。如下图所示:

C语言基本概念(3)_内存_08

从内存的存放顺序,我们可以得出如下图所示的指针结果:

C语言基本概念(3)_计算机_09

从上图可以看出,这时的指针由首地址a+1就是按行了。所以说a+1不再是a[0][1]元素的首地址。这里就有一个内部概念,就是一维数组存储的是二维数组的地址。这里面要演泽起来非常的复杂,但是只要记牢一点,就是多维数组,实际上可以拆分成一个一维数组,这个一维数据存储的是这个多维数组的行元素的首地址。如有一个多维数组a[20][50],那么a[0](a)…a[19]就是行首地址,*[19]+1就是这行的第一个地址。依此类推。因为多维数组可以转化为一维数组存储地址,因此,可以写成如下形式int (*p)[4]来定义出一个二维数组指针变量。

C语言基本概念(3)_内存_10