在函数指针进阶中初步接触了函数指针
现在来深度学习一下
我们来分析两个题目加深一下对函数指针的理解
例1:
(*(void(*)())0)();
分析这个函数的作用是什么?
看到这段语句这么长是不是觉得很难,在我分析了之后就会变得非常简单
分析之前我们先讲解一下C声明的组成
任何C变量的声明都由两部分组成:类型以及一组类似表达式的声明符。
最简单的声明符就是单个变量,如:
double f, g;
这个声明的含义是:当对其求值时,表达式f和g的类型为浮点数类型(double)。
因为声明符与表达式相似,所以我们也可以再声明符中任意使用括号:
double ((f));
这个声明的含义是:当对表达式求值时,((f))的类型为浮点型,由此可以推知,f也是一个浮点类型。
同样的逻辑,也适用与函数和指针类型的声明
如:
double ff();
这个声明的含义是:表达式ff()求值结果,也就是说ff是一个返回值为浮点类型的函数。
double *pf;
这个声明的含义是:*pf是一个浮点数,也就是说,pf是一个指向浮点数的指针。
以上这些声明还可以组合起来
double *g(); //g是一个函数
double (*h)(); //该声明表示h是一个指向的返回值为浮点类型的函数的指针
所以 ( double ( * ) ( ) ) 表示一个“指向返回值为浮点类型的函数的指针”的类型。
回到开始继续分析那个复杂的语句,现在就很简单了
( * ( void ( * ) ( ) ) 0 ) ( ) ;
以 ( *pf ) ( ) 为来看是不是与上述语句有点像
那我们把pf换成0
(*0)();
这样应该是可行的,声明符类似表达式,对吧。但是上式并不能生效,因为运算符*的操作数必须是一个指针,不仅如此这个指针还得是一个函数指针,这样经过运算符*作用后的结果才能作为函数被调用。即:对0作强制类型转换
( * ( void (*) () ) 0 )();
我们来将这个代码简化一下:
typedef void (*funcptr)();
借助typedef语句 用funcptr将void (*)()文本替换掉
现在我们可以将代码写成:
(*(funcptr)0)();
现在是不是更容易理解了
所以上述代码的作用是调用0地址处的函数,一次函数调用
1.将0转换为返回值为void的一个函数的地址
2.调用0地址处的函数
例2:
void(*signal(int, void(*)(int)))(int);
先分析一下,signal先与后面的括号结合,即signal是一个函数名,所以以上代码是一个函数声明
根据上述代码我们可以得到
signal是函数第一个参数是整型,第二个参数是函数指针返回值为void,函数参数为整型,signal返回类型为函数指针返回值为void,函数参数为整型
我们来将代码简化一下:
typedef void (*pf_t)(int)
现在我们可以将代码写成:
pf_t signal(int, pf_t)
其实刚学习的C语言我也觉得函数指针没啥用,但是学到之后就觉得函数指针作用很大
这里给出一段代码,模拟计算机加减乘除
#include <stdio.h>
void test()
{
printf("******************\n");
printf("* 0:退出 1:add *\n");
printf("* 2:sub 3:mul *\n");
printf("* 4:div *\n");
printf("******************\n");
printf("请选择:");
}
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 = 0;
int ret = 0;
do
{
test();
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入操作数:");
scanf("%d%d", &x, &y);
ret = add(x, y);
printf("ret = %d\n", ret);
break;
case 2:
printf("请输入操作数:");
scanf("%d%d", &x, &y);
ret = sub(x, y);
printf("ret = %d\n", ret);
break;
case 3:
printf("请输入操作数:");
scanf("%d%d", &x, &y);
ret = mul(x, y);
printf("ret = %d\n", ret);
break;
case 4:
printf("请输入操作数:");
scanf("%d%d", &x, &y);
ret = div(x, y);
printf("ret = %d\n", ret);
break;
case 0:
printf("退出程序");
break;
default:
printf("选择错误,请重新输入");
}
} while (input);
return 0;
}
这段代码中有很多重复的代码,这使得代码很冗余,可读性减低,无意义的增加了工作量
那我们是不是可以将那些重复的代码封装起来,写成一个函数
->改良之后
#include <stdio.h>
void test()
{
printf("******************\n");
printf("* 0:退出 1:add *\n");
printf("* 2:sub 3:mul *\n");
printf("* 4:div *\n");
printf("******************\n");
printf("请选择:");
}
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;
}
void callback(int (*pf)(int, int))
{
int x, y;
int ret = 0;
printf("请输入操作数:");
scanf("%d%d", &x, &y);
ret = add(x, y);
printf("ret = %d\n", ret);
}
int main()
{
int input = 0;
scanf("%d", &input);
do
{
test();
switch (input)
{
case 1:
callback(add);
break;
case 2:
calc(sub);
break;
case 3:
callback(mul);
break;
case 4:
callback(div);
break;
case 0:
printf("退出程序");
break;
default:
printf("选择错误,请重新输入");
}
} while (input);
return 0;
}
这个代码就巧妙的使用函数指针将重复的内容封装成calc,大大减少了代码量,使得代码简洁很多,可读性变高
calc也有另外一个名称:回调函数
回调函数(callback)的定义
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接实现调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
上面这个说法很复杂,这里的意思就是
标签:函数,int,void,ret,C语言,printf,函数指针,指针 From: https://blog.csdn.net/m0_73634434/article/details/139497076回调函数:回头再掉函数,你把你的函数指针通过传参的形式传递给某个函数,该函数再调用它自身之后再调用你传递的函数