注:本文中的int型变量为32位,占四个字节。
本篇内容旨在对指针数组、数组指针、指针函数、函数指针进行总结,也希望能在总结的同时能有更深入的理解。
数组指针 数组指针顾名思义是个指针,定义形如(*arr)[n]
的一个数组指针,由于()
的优先级最高,所以定义的是一个指针,这个指针指向含有n个元素的数组。
可以设计一个程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> int main (int argc,int * argv[]) { int a[3 ][4 ] = {1 ,2 ,3 ,4 , 5 ,6 ,7 ,8 , 9 ,10 ,11 ,12 }; int (*arr)[4 ] = a; printf ("arr = %p\n" ,arr); printf ("a[0][0] = %p\n" ,&a[0 ][0 ]); printf ("ADDR(a[0][1]) = %p\n" ,&a[0 ][1 ]); printf ("arr[1] = %p\n" ,++arr); printf ("a[1] = %p\n" ,a[1 ]); return 0 ; }
运行程序后输出结果如下:
1 2 3 4 5 arr = 0x7ffefffb8810 a[0 ][0 ] = 0x7ffefffb8810 ADDR(a[0 ][1 ]) = 0x7ffefffb8814 arr[1 ] = 0x7ffefffb8820 a[1 ] = 0x7ffefffb8820
可以看到,初始化了arr后,其值与数组a[][]的首地址相同,而对arr的自增操作则使其值跳跃了整个数组的长度,该操作等同于二维数组a[][]的行地址加1,而进行如果下标操作a[0][1],该元素的地址相对于a[0][0]只是增加了四个字节,即一个int型变量的长度。
我们可以很清晰的从下图理解数组指针:
指针数组 指针数组的概念就相对简单,指针数组是个数组,只不过内部存的元素都是指针类型,由于[]
的优先级要高于*
,所以该数组的定义形如*arr[n]
。
例子如下:
1 2 3 4 5 6 7 8 9 #include <stdio.h> int main (int argc,int * argv[]) { int a = 5 ,b = 10 ; int *arr[] = {&a,&b}; printf ("a = %d,b = %d\n" ,*(arr[0 ]),*(arr[1 ])); return 0 ; }
程序输出结果如下:
数组指针没有什么难度,只是用数组去存指针而已。
函数指针 函数指针其实在编程中相当有用,我们可以将函数的形参声明为函数指针,从而可以将函数的地址传入。
函数作为参数传递跟变量传递一样有两种方式:值传递,地址传递。但是值传递有一个不好之处在于太占用空间,假设在A函数中声明一个形如B函数的形参,而非形如B函数的函数指针,那么将B函数作为参数传入时,就要分配整个B函数的空间给该参数,而函数指针则只会传入一个地址。那么还有一个问题,在函数内部进行函数调用也是一样,而且不会进行值传递,但是在函数内部进行调用,不够灵活,同一类函数可以实现的功能不一样,形如B函数的函数功能和函数名可能有所不同,而每次调用不同的函数时都要去改变A函数未免太不方便,所以才要把函数地址当作参数进行传入。
设计一个程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> int cmp_min (int x,int y) { return x < y?x:y; } int cmp_max (int x,int y) { return x > y?x:y; } int cmp (int x,int y,int (*compare)(int ,int )) { return (*compare)(x,y); } int main (int argc,int * argv[]) { int a = 5 ,b = 10 ; printf ("the min of a,b is %d\n" ,cmp(a,b,cmp_min)); return 0 ; }
输入结果如下:
值得一提的是,函数指针是一个指针,我们不能在声明函数指针的同时进行函数的定义,因为我们只是声明一个指针,我们只能声明一个函数指针,然后用一个定义过的函数去对该指针进行初始化,就像下面这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> int cmp_min (int x,int y) { return x < y?x:y; } int main (int argc,int * argv[]) { int a = 5 ,b = 6 ; int (*compare)(int ,int ) = cmp_min; printf ("the min of a,b is %d\n" ,(*compare)(a,b)); return 0 ; }
输出结果跟上面一样。
其实函数指针可以和指针数组结合起来使用,我们都知道函数名单独使用其实是一个地址,所以可以将其作为指针存于指针数组中,通过数组对其进行访问。
例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h> int cmp_min (int x,int y) { return x < y?x:y; } int cmp_max (int x,int y) { return x > y?x:y; } int cmp (int x,int y,int (**compare)(int ,int )) { printf ("the min of a,b is %d\n" ,(*compare[0 ])(x,y)); printf ("the max of a,b is %d\n" ,(*compare[1 ])(x,y)); } int main (int argc,int * argv[]) { int a = 5 ,b = 10 ; int (*arr[])(int ,int ) = {cmp_min,cmp_max}; cmp(a,b,arr); return 0 ; }
输出结果如下:
1 2 the min of a,b is 5 the max of a,b is 10
在cmp(int x,int y,int (**compare)(int,int))
中声明的函数形参使用了指针的指针,因为我们传入的是是数组的地址,需要先解引用获得数组内的函数地址,所以使用了指针的指针,也可以使用另一种形式:*compare[](int,int)
,效果等同;如果我们在传参时使用了数组下标,则可以不用如此声明,直接声明为cmp(int x,int y,int (*compare)(int,int))
即可。
指针函数 指针函数是个函数,只不过返回值是个指针类型,这也是一个比较简单的概念,就像变量返回一样,指针函数的定义形如*func()
。