进阶指针(二)

图片来源于网络
#国庆发生的那些事儿#

✨博客主页:小钱编程成长记
🎈博客专栏:进阶C语言
🎈推荐相关博文:进阶指针(一)

6.函数指针数组

数组是一个存放相同类型数据的存储空间,我们先来回顾一下已经学过的指针数组。

以整型指针数组为例:
把整型数据的地址存到一个数组中,数组中每个元素都是int* 类型的,这种数组就叫作整型指针数组。

//以整型指针数组为例
int a = 0;
int b = 0;
int c = 0;
int* parr[3] = { &a, &b, &c };//整型指针数组,把整型数据的地址存到数组中,数组名为parr,数组中有3个元素,每个元素都是int* 类型的。

函数指针数组和整型指针数组是类似的。

函数指针数组:
把函数的地址存到一个数组中,数组中每个元素都是函数指针类型的,这种数组就是函数指针数组。

int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int(*pfarr[2])(int, int) = { Add, Sub };//函数名也是函数的地址
//函数指针数组---数组名为pfarr,数组中有2个元素,数组中元素是函数指针类型的类型为int(*)(int, int),函数指针指向的函数参数是int类型的,返回类型也是int类型的。

函数名也是函数的地址;
函数指针数组------数组名为pfarr,数组中有2个元素,数组中元素是函数指针类型的类型为int(*)(int, int) ,函数指针指向的函数参数是int类型的,返回类型也是int类型的,类型中的参数可写可不写,但参数类型一定要写。

注: 函数指针数组的用途:转移表

6.1例子

写一个有+ - * / 四种功能的计算器程序。

//计算器
#include <stdio.h> 
void mune()
{
	printf("********************\n");
	printf("*** 1.add  2.sub ***\n");
	printf("*** 3.mul  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 = 0;
	int b = 0;
	int ret = 0;
	do
	{
		mune();
		printf("请选择:");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			printf("请输入操作数:");
			scanf("%d %d", &a, &b);
			ret = add(a, b);
			printf("%d\n", ret);
			break;
		case 2:
			printf("请输入操作数:");
			scanf("%d %d", &a, &b);
			ret = (a, b);
			printf("%d\n", ret);
			break;
		case 3:
			printf("请输入操作数:");
			scanf("%d %d", &a, &b);
			ret = mul(a, b);
			printf("%d\n", ret);
			break;
		case 4:
			printf("请输入操作数:");
			scanf("%d %d", &a, &b);
			ret = div(a, b);
			printf("%d\n", ret);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);

	return 0;
}

我们可以观察到用switch写有点冗余,若计算函数增多,则switch语句会越来越长。
我们发现这些计算函数的参数个数、类型,和返回类型都一样。可以写成写成函数指针数组
将计算函数写成函数指针数组的形式在main函数中使用,会比使用switch语句更加简洁。

使用函数指针数组实现计算器:

思路:

  1. 写个菜单, 1 ~ 4是计算,0是退出程序,其它的数字是输入错误。
  2. 写四个计算函数。
  3. 使用do…while循环。
  4. 将四个函数存到函数指针数组,用函数指针数组中的元素进行调用函数计算。
#include <stdio.h>
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;
	do
	{
		menu();
		int(*pfunarr[])(int, int) = {NULL, Add, Sub, Mul, Div};//函数指针数组在这种场景下称为转移表。
		//数组中多存一个空指针NULL,是为了将函数地址的下标挤到1 ~ 4方便使用这些函数地址。
		
		printf("请选择:");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
			printf("请输入:");
			scanf("%d %d", &x, &y);
			int ret = pfunarr[input](x, y);
			printf("%d\n", ret);
		}
		else if(input == 0)
		{
			printf("退出程序\n");
		}
		else
		{
			printf("选择错误\n");
		}
		printf("\n\n");
	} while (input);
	return 0;
}
使用函数指针数组有一个约束条件: 这些函数的参数类型、个数,返回类型必须都一样。

7.指向函数指针数组的指针

指向函数指针数组的指针是一个指针
指针指向一个数组,数组的元素都是函数指针

我们先想一想指向整型指针数组的指针:

int* arr[] = { &a, &b, &c };
int* (*p)[3] = &arr;//这里[]里的数据一定要写
//p先与*结合,说明p是指针,
//再与[]结合,说明p指向的是数组,数组中有三个元素,元素的类型是int*; 
//p中存放的是数组的地址。

指向函数指针数组的指针也是类似的:

int (*pfarr[])(int, int) = { NULL, Add, Sub, Mul, Div };
p = &pfarr;
//如果p是指针,那么p就是能够指向函数指针数组pfarr的指针
//指针p的类型是什么呢?
//p是指针,p指向的是数组,数组中有5个元素,元素是函数指针类型的,类型为int (*)(int, int)
//所以p的类型为int (*(*)[5])(int, int)
int (*(*p)[5])(int, int) = &pfarr;//p首先和*结合说明p是指针
类型中的[]里的元素个数一定要写,而且要写对;这个数据一变,整个类型也会发生改变。

8. 回调函数(上)

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

8.1举例:

将计算两个数的过程专门用一个函数封装起来,将四个计算函数的指针作为参数传递给封装函数,在封装函数内用函数指针调用计算函数进行运算,此时计算函数就被称为回调函数。

#include <stdio.h>

//菜单
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 calc(int(*pf)(int, int))
{
	int x = 0;
	int y = 0;
	printf("请输入:");
	scanf("%d %d", &x, &y);
	int ret = pf(x, y);//此时pf指向的函数叫作回调函数
	printf("%d\n", ret);
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
			int(*pfarr[])(int, int) = { NULL, Add, Sub, Mul, Div };
			calc(pfarr[input]);
		}
		else if (input == 0)
		{
			printf("退出程序\n");
		}
		else
		{
			printf("输入错误\n");
		}
		printf("\n\n");
	} while (input);
	return 0;
}

图解:
在这里插入图片描述

总结

本篇文章我们学习了函数指针数组,指向函数指针数组的指针,一小部分回调函数,还有计算器的实现和优化。感谢大家的阅读!大家一起进步!

点赞收藏加关注,C语言学习不迷路!
图片来源于网络

  • 33
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 32
    评论
评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值