- 一、引例
- 二、函数指针
- 函数的地址
- 函数指针的写法
- 函数指针的调用
- 三、函数指针数组
- 函数指针数组的写法
- 函数指针数组的应用---小型计算器
- 四、回调函数
- 结语
#includeint sum(int x,int y) { return x+y; } int main() { int(*p)(int,int)=∑ printf("%dn",p(2,3)); return 0; }
程序运行后输出为 5.
我们没有通过sum直接调用函数,而是通过一个指针调用了函数sum。我们把 这种指向函数的指针叫做函数指针。
函数指针:指向函数的指针!
(存放函数的地址)
函数指针是指向函数的地址,那函数真的有地址吗?
我们打印来看看:
printf("%pn",&sum);
我们发现,函数果然存在一个地址。这个地址指向了sum函数。
我们在学习数组时知道 &arr 与 arr都是数组首元素的地址。那函数的地址是否类似呢?
我们再来看看:
printf("%pn",&sum); printf("%pn",sum);
果然如此,&sum与sum都指向了同一个地址。
结论:取地址函数名和函数名都是函数的地址。
那么,我们该如何写一个函数指针呢?
是这样吗?
int* p(int int)=sum;
我们发现,这样是不行的。
这样写的话p会首先与括号先结合,让p变成了个函数名,int* 变成了返回类型。这样是不对的。
所以我们需要写个括号把*与p结合变成个指针:
int (*P)(int,int)=sum;
这段代码的意思是,我定义了个指针 *p 它指向了函数 sum,函数形参是 (int,int),函数的返回值是最前面的int;
也可以写成:
int (*P)(int x,int y)=sum;函数指针的调用
printf("%dn",(*p)(2,3));
我们就只需要 对指针p进行解引用 (*p),就是所要函数,再输入实参 (2,3),即可计算出结果。
我们再来看下一段代码:
printf("%dn", (p)(2, 3)); printf("%dn", (*p)(2, 3)); printf("%dn", (**p)(2, 3)); printf("%dn", (***p)(2, 3));
我们发现不管有没有,有几个 * 都对调用没有影响。
为什么没有 * 也可以调用函数呢?
printf("%dn", p(2, 3)); printf("%dn", sum(2, 3));
我们发现,其实p与sum都指函数的地址,所以说,没有对p进行解引用都可以调用函数。
注意:
printf("%dn",*p(2, 3));
不可以这样写!!
p(2,3)先结合,已经返回了int类型的值,不可再解引用!!
前面我们学习了数组,数组是存储同一种数据类型多个元素的集合。那我们可不可以写一个数组,数组的每个元素都是一个函数指针呢?
#includeint 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 main() { int(*parr[3])(int x, int y) = { add,sub,mul }; int i = 0; for (i = 0; i < 3; i++) { printf("%dn", parr[i](2, 3)); } return 0; }
结果正确。
int(*parr[3])(int x, int y) = { add,sub,mul };
我们来分析一下这个定义。
parr首先与[3]结合变成一个数组,数组名parr,元素个数3;
剩下的 int(*)(int x, int y) 就是一个函数指针类型。
我们就这样,定义了一个函数指针数组。
我们就能够通过访问数组元素来调用数组里的每个函数了。
学过这些内容后,我们不妨可以试试,使用函数指针数组,写一个可以进行加减乘除的计算器。代码如下:
#include四、回调函数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 menu() { printf("**************************n"); printf("**** 1. add 2. sub ****n"); printf("**** 3. mul 4. div ****n"); printf("**** 0. exit ****n"); printf("**************************n"); } int main() { int input = 0; do { menu(); int x = 0; int y = 0; int ret = 0; int(*p[5])(int, int) = { 0,Add,Sub,Mul,Div }; printf("请选择:>"); scanf("%d", &input); if (input == 0) { printf("退出程序n"); break; } else if (input >= 0 && input <= 4) { printf("请输入2个操作数>:"); scanf("%d %d", &x, &y); ret = p[input](x, y); printf("sum = %dn", ret); } else { printf("选择错误,请重新选择n"); } } while (1); return 0; }
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。
#includeint Add(int x, int y) { return x + y; } int Sub(int x, int y) { return x - y; } int clac(int (*p)(int, int),int x,int y) { return p(x, y); } int main() { int x = 2, y = 3; printf("%dn", clac(Add, x, y)); printf("%dn", clac(Sub, x, y)); return 0; }
我们发现,我们通过给clac函数传递了Add或Sub的地址,与整型变量x,y来实现了回调函数的应用。
int x = 2, y = 3; int (*pa)(int, int) = Add; int (*pb)(int, int) = Sub; printf("%dn", clac(pa, x, y)); printf("%dn", clac(pb, x, y));
我们也可以这样写来传递Add与Sub函数的地址。
结语函数指针的内容就介绍到这里吧,感谢各位读者的阅读,如果觉得笔者写得还可以的话,麻烦各位友友们一键三连哦!非常感谢!如果笔者这篇文章有什么错误和不足的地方,也恳请大家不吝赐教!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)