如题,本篇文章重点讲解C语言中的数组指针和函数指针。这2种指针其实都不是很常用,个人感觉使用起来代码的可读性不是很高,但是还是需要了解一下。
数组指针
数组指针,即指向数组的指针,是用来存放数组的地址的。那如何取出数组的地址呢?直接&数组名
即可。如:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
&arr; // 取出数组的地址
这里的&arr,就能得到数组的地址。如果我们想把它存起来,就需要一个数组指针变量。写法如下:
int (*p)[10] = &arr;
解释一下。首先,括号是不能省略的。如果写成int *p[10]
,就是个指针数组了,这个数组可以存放10个整形指针变量。
括号把*
和数组指针变量名p
括起来,此时p
会优先和*
结合,就是一个指针。把(*p)
去掉,剩下的int [10]
就是数组的类型,表示这个数组指针变量指向的数组存储int
类型的数据,容量是10。
这个数组指针类型是:把变量名p去掉后的int (*)[10]
。
数组指针应该如何使用呢?这里举一个二维数组传参的例子。比如,我们有一个三行五列的二维数组,请你写一个函数,使用指针来打印这个数组里的值。
int arr[3][5] = {{1,2,3,4,5}, {11,22,33,44,55}, {111,222,333,444,555}};
Print(arr, sizeof(arr)/sizeof(arr[0]), sizeof(arr[0])/sizeof(arr[0][0]));
函数Print的形参应该如何写呢?如果是用一个二维数组接收,我相信大家应该是会写的,但是如果要用指针来接收呢?这个指针是什么类型的呢?
数组传参,数组名表示首元素的地址,二维数组的首元素就是第一行!也就是说,二维数组arr的数组名表示第一行的地址,而第一行是一个含有5个int的一维数组。再换句话说,arr作为二维数组的数组名,表示的是一个含有5个int的一维数组的地址,所以需要一个数组指针来接收,这个数组指针指向一个含有5个Int的一维数组!
void Print(int (*p)[5], int r, int c)
{}
函数体实现的关键就是,如何使用数组指针p来遍历原来的二维数组arr。其实呀,既然是数组名作为参数传过来,就可以当成正常的数组那样使用,比如p[i][j]
其实就表示第i行第j列的元素。在C语言中,a[i]
就等价于*(a+i)
,所以p[i][j]
就等价于*(*(p+i)+j)
,所以一下2种实现是等价的。
void Print(int(*p)[5], int r, int c)
{
for (int i = 0; i < r; ++i)
{
for (int j = 0; j < c; ++j)
{
// 写法1
//printf("%d ", p[i][j]);
// 写法2
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
}
如果用数组指针的角度来理解*(*(p+i)+j)
,应该怎么想呢?p
是数组第一行的地址,p+i
就是数组第i行的地址,*(p+i)
就拿到了数组的第i行,相当于拿到了数组第i行的数组名,也就是数组第i行第一个元素的地址。那么,*(p+i)+j
就是数组第i行第j个元素的地址,*(*(p+i)+j)
就是数组第i行第j个元素。
函数指针
函数指针和数组指针非常像。数组指针是指向数组的指针,函数指针则是指向函数的指针。也就是说,函数指针是用来存放函数的地址的。
如何取得函数的地址呢?有2中方法:
- 函数名就表示函数的地址。
&函数名
也表示函数的地址。
比如:
int Add(int x, int y)
{
return x + y;
}
对于Add函数,Add
和&Add
都能得到它的地址。那么,存放这个地址的函数指针应该如何写呢?
int (*p1)(int, int) = Add;
int (*p2)(int, int) = &Add;
和数组指针非常类似。用括号把*
和p
括起来,表示p是一个指针,去掉(*p)
后得到的int (int, int)
就是这个指针指向的函数的类型,即参数是int, int
,返回类型是int
的函数。
这个函数指针类型名是:把变量名去掉后的int (*)(int, int)
。
使用函数指针可以调用函数,有2种调用方式:
- 不解引用,直接调用:
p(3, 5)
- 解引用后再调用:
(*p)(3, 5)
比如,以上的代码可以这么写:
int (*p)(int, int) = Add;
int ret1 = p(3, 5);
int ret2 = (*p)(3, 5);
其实这个解引用操作没啥用,你哪怕写int ret2 = (***************p)(3, 5);
,效果和不加*
是一样的。
总结
- 数组指针是指向数组的指针,数组指针类型由3部分构成:用括号把变量名和
*
括起来表示是一个指针,左边写指针指向的数组存储的元素的类型,右边用方括号表示指向的数组的容量。 - 函数指针是指向函数的指针,函数指针类型由3部分构成:用括号把变量名和
*
括起来表示是一个指针,左边写指针指向的函数的返回类型,右边用圆括号表示函数的形参列表。 - 这两货确实挺像。
感谢大家的阅读!