“指针”概念的解读

指针一般情况下根据语境的不同有两种意思,即地址和指针变量。举个例子:

int a = 20;

int* p = &a;

可以看到,a是一个整形变量,p是一个整形指针变量,p里面存储的是a的地址。我们可以说,p是一个指针,这里是指:p是一个指针变量;我们也可以说,&a是一个指针,这里是指:&a是一个地址。所以关于指针的概念,我们根据实际情况来区分。

指针基础

1.还是上面那个例子,我们将a的地址赋给p时,我们可以写成:int* p = &a;

我们也可以写成:int *p = &a;这两种写法有着不同的理解,但都是正确的。

第一种的理解是:我们创建了一个变量p,他的类型是int*,即整形指针类型;

第二种写法的理解是:我们创建了一个变量p,当p与*结合时,则代表他是一个指针变量,最后与int 结合,则代表他是一个存储着整形变量地址的指针变量。

这两种写法和相应的理解都是正确的,但是我个人认为,第二种写法,更有助于理解后面的指针进阶部分的内容。

2.在创建变量时,*代表创建的是指针变量;在使用时,*则代表解引用操作,即取出相应地址的值。

指针进阶

1.指针数组与数组指针

        从字面意思看,指针数组,可以确定他是一个数组。举例子:int  *p[10],我们知道[]的优先级是最高的,所以这里p和[10]结合,则代表p是一个数组,然后作为一个整体再与*结合,则代表该数组是一个指针数组,即存储指针的数组,很明显,这里的指针是指地址的意思,所以指针数组就是存储地址的数组,这个例子里,p就是一个可以存储10个地址的数组.

        同理,数组指针,我们可以确定,他必然是一个指针,这里说的指针,则代表指针变量的意思。例如:int (*p)[10].我们可以看到,由于括号的存在,p首先和*结合,我们已经说过,此时代表p是一个指针变量,然后再与[10]结合,则代表这个指针变量是指向一个数组的,而这个数组的长度为10,且存储的值是int.综上所得,p是一个指向长度为10的整形数组的指针变量。

2. 关于数组名的理解

int arr1[5] = {1,2,3,4,5};

int arr2[2][5] = {1,2,3,4,5,2,3,4,5,6};

可以看到,我们分别创建了一个一维数组和一个二维数组。不论是一维数组还是二维数组,他们的数组名均代表首元素的地址,只不过不同的是,一维数组的数组名(arr1)代表首元素1的地址。而二维数组的数组名(arr2)代表首元素(即第一行)地址。所以,使用*进行解应用是,*arr1取出的是1的值。而*arr2取出的是{1,2,3,4,5}这个一维数组。我们可以简单写个代码看一下。

c语言中的指针总结_数组

c语言中的指针总结_指针变量_02编辑

可以看到,arr1+1后移动了4个字节,arr2+1后移动了BC-A8=14(16进制)=20(十进制)个字节,而arr2每一行是5个元素,恰好是20个字节,正好印证了上述的说法。

3.两种传参方式(传数组+传指针)

1.数组传参:

c语言中的指针总结_二维数组_03

        可以看到arr1是一个整型数组,当把arr1做为参数传入test函数时,我们可以用一个数组来接受,所以图片中的1是正确的。我们还说过,数组名代表首元素的地址,所以我们也可以用一个一级指针变量来接收,所以2也是正确的。

        我们可以看到,arr2是一个指针数组,所以传参时,我们也可以用一个指针数组来接收,则3是正确的。同样数组名arr2代表首元素的地址,而这个首元素的值又本身是个地址值,所以首元素的地址相当于是,地址的地址,因此我们也可以用一个二级指针变量来接收,因此有了4。

同样,我们再来看看二维数组传参。

c语言中的指针总结_指针变量_04

        可以看到,给test函数传入了arr这个二维数组,则我们接收的时候可以用二维数组接收,所以1正确(二维数组的行可以省略,列不可以省略)。

        我们说,数组名代表首元素的地址,所以我们可以用一个指针变量来接收。但是,二维数组名代表第一行的地址,而每一行则是一个一维数组,所以我们这里可以用指针变量来接收,只不过,这个指针变量必须是一个指向一维数组的指针变量,即前面说过的数组指针,因此4也是正确的,而2是一个一级指针,5是一个二级指针,与传的参数并不匹配。

2.指针传参

c语言中的指针总结_数组_05

没什么说的,传入的是什么类型的指针,接收也必须是什么类型的指针。

4.函数指针 

函数指针由于不存在首元素的概念,所以“&函数名”和“函数名”都可以表示这个函数的地址,所以说,函数名有两层含义,既可以代表这个函数,也可以代表这个函数的地址,举个例子看一下。

c语言中的指针总结_二维数组_06

这里需要注意一下,关于函数指针变量的创建的格式,即图中创建pa的格式。

通过运行的结果,我们可以发现,对pa解应用,函数名,&函数名,三者的效果是一模一样的。