前言
紧接上篇,之前我讲解了指针的进阶详解1,大家没看过的可以先去看那篇,接下来,我来讲一讲指针的另一部分内容:函数指针,函数指针数组和回调函数。
目录
一.函数指针
1.函数指针定义:可以理解为指向函数的地址的指针
有人会问了,函数也有地址吗?答案也是毋庸置疑的,有!那么我来给大家展示一下函数的地址。
#include<stdio.h>
void test() {
return 0;
}
int main() {
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}
在上面的代码中,我随意创建了一个函数,通过打印,函数也有地址 。
总结:函数地址不分首地址和整体地址,函数有且只有一个地址,可以直接用函数名表示,也可以加&符合表示。
而指针的作用就是取出某个变量,数组,指针的地址,那么函数也不例外,由此引出函数指针。
2.函数指针的介绍与写法
int Add(int x, int y) {
return x + y;
}
int main() {
int a, b;
printf("请输入两个操作数:\n");
scanf("%d %d", &a, &b);
int ret = Add(a, b);
这是一般情况下对函数的调用,函数名+()调用操作符,即可使用函数的功能实现;
而函数指针也可以用来调用函数实现其功能:
int Add(int x, int y) {
return x + y;
}
int main(){
//接下来使用函数指针去调用
int (*pf)(int, int) = Add;
printf("方法3的写法:%d\n",pf(2, 3));
printf("方法2的写法:%d\n", (*pf)(2, 3));
printf("普通函数的调用:%d\n", Add(2, 3));
return 0;
}
由此可知我们在main函数中进行函数的调用有两种方法,那么函数指针是如何进行创建的?
函数指针的创建需要根据据函数的返回值类型,函数的参数多少去定义。
例: 在上面的Add函数中,函数的参数有两个,且都是int类型形参,而且函数的返回值类型是int型,指针肯定是*,那么随便起一个指针名就行。通过这几个信息我们就可以创建函数指针。
函数指针的类型为:(填写指向函数的返回值类型)(*)(填写指向函数的参数数量);
(你们可以理解为万能模板,以后写函数指针就可以采用这个模板复刻!hhh).
3.函数指针的用途
用人会问:函数指针这么麻烦,还不如就用普通函数法去调用。这是因为我们现阶段接触的代码并不算多,等级也不算高,若是以后在公式做项目时,项目会有成千上万行的代码,函数也多得不计其数,使用函数指针就可以简化调用步骤。下面来给大家看一看使用函数指针到底有什么好处?
#include<Windows.h>
#include<stdio.h>
void menu() {
printf("**********计算器使用界面*************\n");
printf("**************1.Add.*****************\n");
printf("**************2.Sub.*****************\n");
printf("**************3.Mul.*****************\n");
printf("**************4.Div.*****************\n");
printf("**************0.exit.****************\n");
}
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 input = 0;
int a, b;
int ret = 0;
do {
menu();
printf("请输入你的选择:\n");
scanf("%d", &input);
switch (input) {
case 1:
printf("请输入两个操作数:\n");
scanf("%d %d", &a, &b);
int ret = Add(a, b);
printf("%d\n", ret);
break;
case 2:
printf("请输入两个操作数:\n");
scanf("%d %d", &a, &b);
ret=Sub(a, b);
printf("%d\n", ret);
break;
case 3:
printf("请输入两个操作数:\n");
scanf("%d %d", &a, &b);
ret = Mul(a, b);
printf("%d\n", ret);
break;
case 4:
printf("请输入两个操作数:\n");
scanf("%d %d", &a, &b);
ret = Div(a, b);
printf("%d\n", ret);
break;
case 0:
printf("即将退出计算器\n");
exit(0);
default:
printf("输入错误\n");
break;
}
} while (input);
return 0;
}
以上代码为计算器的功能实现方式,我们可以在主函数中看到switch多分支选择语句case中有着大量的代码冗余,造成了空间上的巨大浪费,现在只是写了加减乘除四个功能,若是再加十多个异或,左右移,按位与或等功能,代码量想必会更加多。这时,就到了函数指针关键救场的时候了,通过函数指针可以优化冗余代码,使每个分支语句的计算器功能只用一条语句实现,如下:
#include<stdio.h>
#include<Windows.h>
void menu() {
printf("**********计算器使用界面*************\n");
printf("**************1.Add.*****************\n");
printf("**************2.Sub.*****************\n");
printf("**************3.Mul.*****************\n");
printf("**************4.Div.*****************\n");
printf("**************0.Add.*****************\n");
}
void calc(int(*pf)(int ,int)) {
int a, b;
int ret = 0;
printf("请输入两个操作数:\n");
scanf("%d %d", &a, &b);
ret = pf(a, b);
printf("%d\n", ret);
}
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 input = 0;
int a, b;
int ret = 0;
do {
menu();
printf("请输入你的选择:\n");
scanf("%d", &input);
switch (input) {
case 1:
calc(Add);
break;
case 2:
calc(Sub);
break;
case 3:
calc(Mul);
break;
case 4:
calc(Div);
break;
case 0:
printf("即将退出计算器\n");
exit(0);
default:
printf("输入错误\n");
break;
}
} while (input);
return 0;
}
通过创建函数calc,因为加减乘除四个函数的返回值类型,函数参数都相同,由此在calc中创建出函数指针,可以通过函数指针pf 指向加减乘除中的任何一个函数,借此调用该函数,实现其功能,大家可以看到,我只用到了一个函数就可以实现对其他计算器功能函数的调用,大量简化代码,若没有函数指针,我们根本无法做到如此简化的代码,想必大家也都认识到了函数指针的重要性!
二.函数指针数组
1.定义
那要把一个乃至多个函数的地址存到一个数组中,那这个数组就叫函数指针数组
我们来看几个例子,请各位判断一下下列哪个是函数指针数组?
int (*parr1[10])();
int *parr2[10]();
int (*)() parr3[10];
答案其实是第一个,parr1 先和 [] 结合,说明 parr1是数组,数组的内容是什么呢? 是 int (*)() 类型的函数指针。
2. 函数指针数组的用途
它的用途我们还是用刚才对计算器功能实现的代码来看:
其实通过代码我们发现switch多分支选择语句有些多余,我们已经了解了函数指针数组,那我们可以采用数组遍历的方式,数组中既然存入了函数的地址,我们可以通过输入某个数,程序就自动进入到数组的那一个位置,然后去找到该数组元素(函数)的地址,进而调用函数实现该功能!
#include<Windows.h>
#include<stdio.h>
void menu() {
printf("**********计算器使用界面*************\n");
printf("**************1.Add.*****************\n");
printf("**************2.Sub.*****************\n");
printf("**************3.Mul.*****************\n");
printf("**************4.Div.*****************\n");
printf("**************0.exit.****************\n");
}
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 input = 0;
int a, b;
int ret = 0;
//函数指针的数组,将计算机功能都放在数组中,因为下标从0开始,所以数组首元素加个0。
int(*arr[5])(int, int) = {0,Add,Sub,Mul,Div };
while (1) {
menu();
printf("请输入你的选择:\n");
scanf("%d", &input);
if (input>= 1 && input < 5) { //输入哪个数就选择数组中的哪个数,进而调用此数位置的函数
printf("请输入两个操作数:\n");
scanf("%d %d", &a, &b);
ret = arr[input](a, b);
printf("%d\n", ret);
}
else if (input == 0) {
printf("即将退出程序\n");
exit(0);
}
else {
printf("输入错误\n");
}
}
return 0;
}
大家若想增加计算器中的更多功能,只需要写出该功能的函数,扩大数组的大小,将函数地址放入数组,增加input输入值的上限即可,方便又快捷!
三.指向函数指针数组的指针
若是大家看过我前面写的指针进阶详解 (1),想必就知道函数指针数组这又是一个套娃名词,数组指针,数组指针的数组,指向数组指针的数组的指针......实乃无限套娃之无限套娃啊~!!!
名词解析:
指向函数指针数组的指针是一个 指针
指针指向一个 数组 ,数组的元素都是 函数指针 ;
void test(const char* str)
{
printf("%s\n", str);
}
int main()
{
//函数指针pfun
void (*pfun)(const char*) = test;
//函数指针的数组pfunArr
void (*pfunArr[5])(const char* str);
pfunArr[0] = test;
//指向函数指针数组pfunArr的指针ppfunArr
void (*(*ppfunArr)[5])(const char*) = &pfunArr;
return 0;
}
具体的就不再过多讲解了,大家有兴趣的话可以深入了解了解这方面的知识内容。
好了,关于指针的进阶详解2就讲到这里,大家觉得对自己帮助挺大的话,点个赞吧!以后会有更多精彩内容,点个关注不要迷路哟!