• 【C语言】指针详解(3)


    大家好,我是苏貝,本篇博客带大家了解指针(3),如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
    在这里插入图片描述


    一.函数指针数组

    字符数组–数组–存放字符的数组
    整型数组–数组–存放整型的数组
    指针数组–数组–存放指针的数组
    函数指针数组–数组–存放函数指针的数组,即存放函数的地址

    int (* parr1[10])();
    parr1 先和 [ ] 结合,说明 parr1是数组,数组的元素类型是什么呢?将数组名和数组名后面的[ ] 去掉,得到int (* )(),即函数指针,所以数组的元素类型是函数指针

    函数指针数组的用途:转移表
    例子:计算器,实现+ - * / 4个功能

    #include
    
    void menu()
    {
    	printf("********************************\n");
    	printf("******   1.Add   2.Sub    ******\n");
    	printf("******   3.Mul   4.Div    ******\n");
    	printf("******   0.exit           ******\n");
    	printf("********************************\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 x = 0;
    	int y = 0;
    	int ret = 0;
    	do
    	{
    		menu();
    		printf("请选择:");
    		scanf("%d", &input);
    		switch (input)
    		{
    		case 1:
    			printf("请输入2个数:");
    			scanf("%d %d", &x, &y);
    			ret = Add(x, y);
    			printf("%d\n", ret);
    			break;
    		case 2:
    			printf("请输入2个数:");
    			scanf("%d %d", &x, &y);
    			ret = Sub(x, y);
    			printf("%d\n", ret);
    			break;
    		case 3:
    			printf("请输入2个数:");
    			scanf("%d %d", &x, &y);
    			ret = Mul(x, y);
    			printf("%d\n", ret);
    			break;
    		case 4:
    			printf("请输入2个数:");
    			scanf("%d %d", &x, &y);
    			ret = Div(x, y);
    			printf("%d\n", ret);
    			break;
    		case 0:
    			printf("退出程序\n");
    			break;
    		default:
    			printf("选择错误,请重新选择:\n");
    			break;
    		}
    	} while (input);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    但是写完这些代码后我们发现,这些代码有许多重复的地方,所以我们是否可以简化一下呢?

    简化上面的代码,我们发现,Add,Sub,Mul,Div的参数类型和个数相同,返回类型也相同,所以可以使用函数指针数组,让Add,Sub,Mul,Div成为该数组的元素,用数组的元素调用Add,Sub,Mul,Div函数;

    int(*pfArr [ ])(int, int) = { Add,Sub,Mul,Div };

    所以它们的下标分别为0,1,2,3,但由于菜单上1,2,3,4才代表它们,所以我们不妨在Add前加NULL,这样它们的下标就为1,2,3,4了

    int(*pfArr[])(int, int) = { NULL,Add,Sub,Mul,Div };

    总代码:

    #include
    
    void menu()
    {
    	printf("********************************\n");
    	printf("******   1.Add   2.Sub    ******\n");
    	printf("******   3.Mul   4.Div    ******\n");
    	printf("******   0.exit           ******\n");
    	printf("********************************\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 x = 0;
    	int y = 0;
    	int ret = 0;
    	do
    	{
    		menu();
    		printf("请选择:");
    		scanf("%d", &input);
    		int(*pfArr[])(int, int) = { NULL,Add,Sub,Mul,Div };
    		if (0 == input)
    			printf("退出程序\n");
    		else if (input >= 1 && input <= 4)
    		{
    			printf("请输入2个数:");
    			scanf("%d %d", &x, &y);
    			ret = pfArr[input](x, y);
    			printf("%d\n", ret);
    		}
    		else
    			printf("输入错误,请重新输入\n");
    	} while (input);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    上述代码也有缺陷,因为要写成数组元素的话,它们的类型必须要相同,如果有一个函数,它的返回类型不是int,那就不能采用这种方法

    二.指向函数指针数组的指针(不重要)

    经过上面的学习,我们可以知道,指向函数指针数组的指针是一个 指针,指针指向一个 数组 ,数组的元素都是 函数指针,那指向函数指针数组的指针该如何定义呢?

    void(*(*p)[2])(int, int);
    p先与 * 结合,代表p是个指针,再与[ ]结合,表示p指向的是个数组,将( * p)[2]去掉得到void( *)(int, int)是函数指针,所以数组的元素类型是函数指针

    int Add(int x, int y)
    {
    	return x + y;
    }
    
    int Sub(int x, int y)
    {
    	return x - y;
    }
    
    int main()
    {
    	//函数指针
    	int (*pf)(int, int) = Add;
    	//函数指针数组
    	int (*pfArr[2])(int, int) = { Add,Sub };
    	//指向函数指针数组的指针
    	int(*(*p)[2])(int, int);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    三.回调函数

    回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应

    例子:计算器(将上面最开始的计数器代码优化)

    在这里插入图片描述
    我们可以看出,上面红色框里面的大部分代码都冗余,那我们能否使用一个函数cacl()达到实现+ - * / 4个功能的目的呢?

    思路:将实现+ - * / 4个功能的函数作为函数cacl()的形参,用一个函数指针来接收

    void menu()
    {
    	printf("********************************\n");
    	printf("******   1.Add   2.Sub    ******\n");
    	printf("******   3.Mul   4.Div    ******\n");
    	printf("******   0.exit           ******\n");
    	printf("********************************\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;
    }
    
    void cacl(int (*pf)(int, int))
    {
    	int x = 0;
    	int y = 0;
    	int ret = 0;
    	printf("请输入2个数:");
    	scanf("%d %d", &x, &y);
    	ret = pf(x, y);
    	printf("%d\n", ret);
    }
    
    int main()
    {
    	int input = 0;
    	do
    	{
    		menu();
    		printf("请选择:");
    		scanf("%d", &input);
    		switch (input)
    		{
    		case 1:
    			cacl(Add);
    			break;
    		case 2:
    			cacl(Sub);
    			break;
    		case 3:
    			cacl(Mul);
    			break;
    		case 4:
    			cacl(Div);
    			break;
    		case 0:
    			printf("退出程序\n");
    			break;
    		default:
    			printf("选择错误,请重新选择:\n");
    			break;
    		}
    	} while (input);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    先使input==2,所以选择的是减法,输入使得x=10,y=2,通过函数指针pf找到Sub函数,返回8用ret接收,最后输出ret

    在这里插入图片描述


    好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

  • 相关阅读:
    【LeetCode 力扣】3.无重复字符的最长子串 Java实现 滑动窗口
    【spring】BeanFactory的实现
    经验分享:判断字符串的显示宽度
    java毕业设计校园快递代领系统mybatis+源码+调试部署+系统+数据库+lw
    Spring - BeanPostProcessors 扩展接口
    MyBatis-Plus多数据源dynamic-datasource解决多数据源Redis Key 重复问题
    论文翻译 | ITER-RETGEN:利用迭代检索生成协同增强检索增强的大型语言模型
    从零开始 - Docker部署前后端分离项目(四)
    E. Non-Decreasing Dilemma
    EtherCAT从站转modbus RTU协议转换网关用modbus slave测试的方法
  • 原文地址:https://blog.csdn.net/qq_75000174/article/details/132817456