> 文章列表 > 你了解C语言中的数组指针和函数指针吗?

你了解C语言中的数组指针和函数指针吗?

你了解C语言中的数组指针和函数指针吗?

如题,本篇文章重点讲解C语言中的数组指针函数指针。这2种指针其实都不是很常用,个人感觉使用起来代码的可读性不是很高,但是还是需要了解一下。
你了解C语言中的数组指针和函数指针吗?

数组指针

数组指针,即指向数组的指针,是用来存放数组的地址的。那如何取出数组的地址呢?直接&数组名即可。如:

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]);// 写法2printf("%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中方法:

  1. 函数名就表示函数的地址。
  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种调用方式:

  1. 不解引用,直接调用:p(3, 5)
  2. 解引用后再调用:(*p)(3, 5)

比如,以上的代码可以这么写:

int (*p)(int, int) = Add;
int ret1 = p(3, 5);
int ret2 = (*p)(3, 5);

其实这个解引用操作没啥用,你哪怕写int ret2 = (***************p)(3, 5);,效果和不加*是一样的。

总结

  1. 数组指针是指向数组的指针,数组指针类型由3部分构成:用括号把变量名和*括起来表示是一个指针,左边写指针指向的数组存储的元素的类型,右边用方括号表示指向的数组的容量。
  2. 函数指针是指向函数的指针,函数指针类型由3部分构成:用括号把变量名和*括起来表示是一个指针,左边写指针指向的函数的返回类型,右边用圆括号表示函数的形参列表。
  3. 这两货确实挺像。

感谢大家的阅读!