目录:
1.二维数组传参的本质
2.函数指针变量
3.函数指针数组
1.二维数组传参的本质
之前使用二维数组传参
#include <stdio.h>
void test(int a[3][5], int r, int c)
{int i = 0;int j = 0;for(i=0; i<r; i++){for(j=0; j<c; j++){printf("%d ", a[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7}};test(arr, 3, 5);return 0;
}
实际上:在一维数组中,数组名就是数组首元素的地址
而在二维数组中,数组的首元素就是第一行(一维数组)每一行都是一个元素(一维数组)
综上所述:二维数组的数组名就是第一行元素的地址,而第一行又是一个一维数组
因此,又可以将代码改为如下形式
#include <stdio.h>
void test(int (*p)[5], int r, int c)
{int i = 0;int j = 0;for(i=0; i<r; i++){for(j=0; j<c; j++){printf("%d ",*(*(p+i)+j));//改为(*(p+i))[j]) }printf("\n");}
}
int main()
{int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7}};test(arr, 3, 5);return 0;
}
总结:形参部分可以写成数组形式,写可以写成指针形式
arr[i]实际上编译器翻译为*(arr+i)
2.函数指针变量
2.1函数指针变量的创建
#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("test: %p\n", test);printf("&test: %p\n", &test);return 0;
}
首先我们来看这个代码,输出结果是一样的。
这说明函数名就是函数的地址
而我们想要将函数的地址存起来,就得创建函数指针,它与数组指针的创建非常相似
void test(){printf("hehe\n");}void (*pf1)() = &test;void (*pf2)()= test;int Add(int x, int y){return x+y;}int(*pf3)(int, int) = Add;int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的
函数指针类型的解析
2.2函数指针变量的使用
使用时,*pf1也可直接写成pf1
2.3typedef关键字
typedef unsigned int uint;
//将unsigned int 重命名为uint
指针类型
1 typedef int* ptr_t;
但是数组指针和函数指针就有差别了
比如我们有数组指针类型 int(*)[5] ,需要重命名为 parr_t
tepedef int(*)[5] parr-t;//这样是错误的
//数组指针的命名
tepedef int(*parr-t)[5]; //新的类型名必须放在*的右边
函数指针类型的重命名也是⼀样的,⽐如,将 void(*)(int) 类型重命名为 pf_t
typedef void(*pf-t)(int) ;
3.函数指针数组
数组是⼀个存放相同类型数据的存储空间,我们已经学习了指针数组
int *arr[10];
//数组的每个元素是int*
那要把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?
int (*parr1[3])();
int *parr2[3]();
int (*)() parr3[3];
答案是:parr1
parr1 先和 [ ] 结合,说明parr1是数组,数组的内容是什么呢?
是 int (*)() 类型的函数指针。