函数指针与函数指针数组

一:函数指针

1.函数指针的创建

  • 函数指针,定语是函数,本质上是一个指针,合起来就是指向一个函数的指针
  • 创建一个函数指针时我们只要清楚下面这几个点,就可以轻松创建一个函数指针
  1. 函数指针的名字
  2. 函数指针指向的函数的参数类型
  3. 函数指针指向的函数的返回值
  • 下面一个小例子帮你更好的理解如何创建一个函数指针
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int x = 1;
	int y = 2;
	int sum = 0;
	int (*p)(int,int) = &Add;
	sum=(*p)(x, y);
	printf("%d", sum);
	return 0;
}

请添加图片描述

  • 我们首先看到第三行,这里我创建了一个函数叫做Add,两个参数都为int类型,返回值也为int类型

  • 再看到代码的第十二行,这一行我们创建了一个函数指针

  • 其中序号1位置的p是这个函数指针的名字

  • p前面的*代表p是一个指针,后面又跟着一个(),这个括号代表指针p是指向一个函数

  • (*p)后的()里面是 (int,int),对应上方Add函数的两个参数类型

  • (*p)前方的int对应Add函数的返回类型int

  • 强调:(*p)必须要在括号里面,写成 int *p (int,int)=&Add是错误的写法

  • 因为不把p放到括号里面的话,p会先于和后面的()结合,编译器会把p当成一个函数,而不是一个指针

  • 而把p用括号括起来时,表明了p先是一个指针,然后再和后面的括号结合表明这个指针是指向一个函数

  • 同理,使用(p)调用Add函数时也必须在p两旁加上(),否则你会收获一个编译器的报错
    请添加图片描述

  • p存放了Add函数的地址,对p进行解引用(*p)就是找到了Add,(*p)(x,y)等价于Add(x,y)

2.&函数名与函数名

  • 我们知道数组名代表数组首元素的地址,那函数名是不是代表函数首元素的地址呢?
  • 可是函数没有首元素这一说,所以函数名其实就是代表函数的地址
  • 也就是说&Add和Add其实是等价的
    -请添加图片描述
  • 可以看到我把&Add换成Add,结果仍然没有变
  • 我们再想想,Add函数的地址能被函数指针p接收,而Add就代表其地址,那p是不是可以和Add等价呢
  • 请添加图片描述
  • 可以看到,我没有使用(*p)(x,y)而是使用p(x,y),结果仍然正确,编译器也没有报错
  • 说明了p其实是和Add等价的,那么前面的*其实也没有什么作用了
  • 所以我们无论往p前面加多少个*,都不影响我们的结果
  • 请添加图片描述

二:函数指针数组

1.函数指针数组的创建

  • 讲完了函数指针,我们再来看看函数指针数组
  • 函数指针数组,看起来好像很难理解,我们可以这么看(函数指针)数组
  • 说明它本质上是一个数组,但是数组中存放的是函数指针
  • 我们只要把上面创建函数指针的步骤稍稍变一变,就能创建一个函数指针数组
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int main()
{
	int x = 1;
	int y = 2;
	int sum = 0;
	int cha = 0;
	int (*p[2])(int, int) = { Add,Sub};
	sum = p[0](x, y);
	cha = p[1](x, y);
	printf("%d\n", sum);
	printf("%d", cha);
	return 0;
}

请添加图片描述

  • 看到代码的第17行,原本的 int (*p) (int,int)变成了 int (*p[2]) (int,int)
  • 就是在p后面加了个[2],我们就创建了一个函数指针数组
  • 我们可以这么看这一行代码,[] 和的优先级是[]高于,所以p先和[2]结合,表明p是一个数组
  • 然后我们把p[2]摘掉,剩下int (*)(int,int),这代表p这个数组中存放的数据类型
  • 通过上文我们可知,这个类型是一个函数指针,(一个参数为(int,int),返回值为int的函数)的指针
  • 所以p就是一个能够存放两个函数指针的数组
  • 要想调用里面的函数和我们之前使用数组并无区别,通过p[0]就能找到Add函数,再加上参数,就能完成Add函数的调用
  • 而换成p[1]就能调用Sub函数

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

  • 难度再升级一下,我们知道了如何创建一个函数指针数组,那我们想用一个指针存放这个数组,这个指针如何创建呢?
  • 首先我们要明白这个指针指向的是一个函数指针数组,简单说就是指向一个数组,所以这个指针是一个数组指针
  • 我们再把上面创建函数指针数组的代码变一变, 变成 int (*(*p)[2]) (int,int)
  • (*p)说明p是一个指针,后面跟的[2]代表这个指针指向的是一个数组
  • 然后挖去(p)[2],剩下int()(int,int)是这个(数组指针)指向的(数组的元素)的类型为函数指针
  • 一起看就代表了指向一个函数指针数组的数组指针

三:void(*signal(int,void(*)(int)))(int)的意义

  • 有了前面的知识的铺垫,最后再来看看《C陷阱和缺陷》这本书提到的一个代码
  • 这看起来简直复杂极了,我们一层一层看,先看signal(int,void(*)(int))
  • 这样是不是就比较清晰了,signal是函数名,它有两个参数,一个为int,另一个是函数指针(void(*)(int))
  • 这个函数指针指向一个参数为int,返回值为void的函数
  • 然后去掉signal(int,void(*)(int)),剩下void(*)(int)是signal这个函数的返回值的类型
  • 说明signal函数的返回值的类型也是一个函数指针
  • 这个函数指针也指向一个参数为int,返回值为void的函数
  • 或许这样写你会比较清晰void(*)(int)signal(int,void(*)(int)),但是C语言不支持这样的语法
  • 我们可以用typedef帮助我们理解

请添加图片描述

  • 我们讲void(*)(int)这个函数指针类型重定义为abc
  • 然后原本复杂的代码就可以写为abc signal(int, abc);
  • 综上所述,void(signal(int,void()(int)))(int)这句话其实是一个函数signal的声明
  • 12
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dhdw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值