先看一段代码
int Add(int x, int y)
{
return x + y;
}
int main()
{
printf("%p\n", &Add);
printf("%p\n", Add);
return 0;
}
输出结果如下
从上我们可以了解到其实函数名就是一个地址,所以用不用&的结果是一样的,但是地址该如何保存下来呢?
这就涉及到函数指针了,看代码
void test()
{
printf("hehe\n");
}
下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();
pfun1可以存放。pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无 参数,返回值类型为void。
实际例子如下:
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int, int) = Add;
//pf是一个函数指针,该指针指向的是一个函数,指向的函数有两个整形参数,返回值类型为int。
printf("%d\n", (*pf)(1, 2));
printf("%d\n", pf(1, 2));
return 0;
}
输出结果如下
上面说到,既然函数就是用地址来实现功能的,那么我们解引用和不解引用产生的结果当然是一样的。
我们接着来读读下面这个两个代码
//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);
//代码1
(*(void (*)())0)();
我们先将(*(void (*)())0)()进行拆分
(*( )0)()
void(*)()
void(*)()不就是函数指针嘛,该指针指向一个函数,无参数,返回类型为void
那么void(*)()0?是什么意思呢
我们先来了解这个玩意儿(float*)p,p是一个指针,那么这个的意思就是把p强制类型转化为(float*)
回到void(*)()0,它的意思也很简单,就是把0这个整形强制转化为函数指针类型,地址为0。
那么解引用他就是找到这个0地址的内容,是一个函数,无参数,返回类型为void。
即为(*(void (*)())0)()。
示例如下
int test()
{
printf("QQHSJ\n");
return 0;
}
int main()
{
test();
printf("%p\n", test);
(*(int(*)())test)();
return 0;
}
//代码2
void (*signal(int, void(*)(int)))(int);
它实际上就是一个函数声明,跟代码1一样我们来进行拆分
void(* )(int);
signal(int, void(*)(int))
我们先看void(*p)(int),p是一个函数指针,它指向一个函数,参数为int,返回值类型为void。
一般来说我们通常的函数声明是这样的
int Add(int, int);
所以跟上述几乎代码2几乎是一样的,如果实在看不明白,我们就用一种别扭的方式理解,当然了这样的写法在编译器上面是无法通过的。
void(*)(int) signal(int, void(*)(int));
与
int Add(int, int);
对比来看,形式完全是一模一样,所以它完完全全就是一个函数声明。只是返回类型是函数指针类型
就好比这个
int* BALABALA(int,int);,返回类型是整形指针类型。
但是void(*)(int) signal(int, void(*)(int));这种形式是可以实现的,但是需要用到typedef
如下
typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);
数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组, 比如:
int *arr[10];
//数组的每个元素是int*
那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?
int (*parr1[10])();
parr1 先和 [] 结合,说明parr1是数组,数组的内容是什么呢? 是 int (*)() 类型的函数指针。
如果觉得还不明确,用typedef替换
typedef int(* pfun_int)();
pfun_int parr1[10];
这样是不是清楚多了。
具体应用如下,加减乘除的计算代码
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
int main()
{
int x, y;
int input = 1;
int ret = 0;
int(*p[5])(int x, int y) = {
0, Add, Sub, Mul, Div }; //转移表
while (input)
{
printf("**************************\n");
printf("**1:add************2:sub**\n");
printf("**3:mul************4:div**\n");
printf("**************************\n");
printf("请选择:");
scanf("%d", &input);
if ((input <= 4 && input >= 1))
{
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = (*p[input])(x, y);
}
else
printf("输入有误\n");
printf("ret = %d\n", ret);
}
return 0;
}
真是越走越远啊,难度确实蛮大的,大家好好学吧。柒柒没办法讲清楚的话,还望大家多抽点时间去看看书或者视频。
指向函数指针数组的指针是一个指针,指针指向一个数组 ,数组的元素都是函数指针 ;
看代码
void test(const char* str)
{
printf("%s\n", str);
}
int main()
{
//函数指针pfun
void (*Pfun)(const char*) = test;
//函数指针的数组PfunArr
void (*PfunArr[5])(const char*);
pfunArr[0] = test;
//指向函数指针数组PfunArr的指针PPfunArr
void (*(*PPfunArr)[5])(const char*) = &PfunArr;
return 0;
}
大家可能对第三个抱有非常大的疑问,解释如下
其实我们依旧可以用typedef的方式替换,从而理解“指向 函数指针数组 的 指针”
typedef void(*Void_Char)(const char*)
Void_Char PfunArr[5]
Void_Char PfunArr[5]它的意思就是PfunArr是一个数组,它的类型为Void_Char。
我们再回忆一下数组指针是怎么定义的
int arr[5] = {
0 };
int (*p)[5] = &arr
那么要实现指针指向这个数组是不是变得异常简单了,即为
Void_Char *PPfunArr[5] = &PfunArr;
这样看是不是清楚很多了,我们再将它展开不就得到了void (*(*PPfunArr)[5])(const char*) = &PfunArr;
关于这一部分,可能还要小小的地方没有继续扩展,即回调函数和指针和数组的解析
回调函数,我会专门详细的写一段代码,配上注释的情况下供小伙伴们阅读。
指针和数组的解析,部分代码如下,大家可以想想它输出的结果如何?
int a[] = {
1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
欢迎大家共同探讨,如有什么不对的地方也请大家指出哦~