指针进阶–函数指针

一、引例

#include<stdio.h>
int sum(int x,int y)
{
return x+y;
}
int main()
{
int(*p)(int,int)=&sum;
printf("%dn",p(2,3));
return 0;
}

程序运行后输出为 5.
在这里插入图片描述

我们没有通过sum直接调用函数,而是通过一个指针调用了函数sum。我们把 这种指向函数的指针叫做函数指针
函数指针:指向函数的指针!
(存放函数的地址

二、函数指针

函数的地址

函数指针是指向函数的地址,那函数真的有地址吗?
我们打印来看看:

	printf("%pn",&sum);

在这里插入图片描述
我们发现,函数果然存在一个地址。这个地址指向了sum函数。
在这里插入图片描述

我们在学习数组时知道 &arrarr都是数组首元素的地址。那函数的地址是否类似呢?
我们再来看看:

	printf("%pn",&sum);
	printf("%pn",sum);

在这里插入图片描述
果然如此,&sumsum都指向了同一个地址。
结论:取地址函数名和函数名都是函数的地址。

函数指针的写法

那么,我们该如何写一个函数指针呢?
是这样吗?

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类型的值,不可再解引用!!

三、函数指针数组

前面我们学习了数组,数组是存储同一种数据类型多个元素的集合。那我们可不可以写一个数组,数组的每个元素都是一个函数指针呢?

#include<stdio.h>
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 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<stdio.h>
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;
		printf("请选择:>");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			printf("请输入2个操作数>:");
			scanf("%d %d", &x, &y);
			ret = Add(x, y);
			printf("sum = %dn", ret);
			break;
		case 2:
			printf("请输入2个操作数>:");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			printf("sum = %dn", ret);
			break;
		case 3:
			printf("请输入2个操作数>:");
			scanf("%d %d", &x, &y);
			ret = Mul(x, y);
			printf("sum = %dn", ret);
			break;
		case 4:
			printf("请输入2个操作数>:");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			printf("sum = %dn", ret);
			break;
		case 0:
			printf("退出程序n");
			break;
		default:
			printf("选择错误,重新选择!n");
			break;
		}
		
	} while (input);
	return 0;
}

四、回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。

#include<stdio.h>
int 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函数的地址。

结语

函数指针的内容就介绍到这里吧,感谢各位读者的阅读,如果觉得笔者写得还可以的话,麻烦各位友友们一键三连哦!非常感谢!如果笔者这篇文章有什么错误和不足的地方,也恳请大家不吝赐教!
在这里插入图片描述

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>