C语言:函数指针

C语言:函数指针,从懵逼到精通

我们知道,指针是一个地址,C语言中想要取出地址就需要用到&.

int a = 0;取整形指针出来就是 &a;

int arr[] = {0};取数组指针出来就是&arr;

而函数指针也不例外

创建了函数: int fx(int a,int b);

则把函数地址取出来就应该是&fx

那么这里还需要引入一个知识

我们知道arr数组名=数组首元素地址

因此我们知道:arr不加&也是一个地址(数组首元素地址)

但是arr != &arr

(1条消息) C语言:数组指针_srhqwe的博客-CSDN博客

那么函数名呢?

所以这里我们可以看到

fx == &fx

所以我们就知道:

①数组名 != &数组名

②函数名 == &函数名

讨论完函数的地址,则就需要引入存放函数地址的指针

为了方便观察

创建一个数组以及一个函数

int arr[10];

int fx(int a,int b);

结合数组指针的知识,我们可以知道

(*p)表示这是一个指针

函数名():表示一个函数

数组名[]: 表示一个数组

| |

| |

(*p)[]表示的是指向数组的指针

[]表示数组这是我们知道的,那么()就应该表示函数

(*p)()就表示的是指向函数的指针

同样地,我们知道,数组的类型,就是数组指针的类型

int (*p)[]

那么也可以推出,函数的类型,就是函数指针的类型

int (*p)()

而我们还知道,数组指针[]中,需要写上原数组[]中的参数

int (*p)[10];那么此时就是一个数组指针

| |

那么在函数指针()中,应该也需要填上,原函数()中的参数。

但是,这里并不需要填写完整,只需要填写,原函数()中的类型,那么也就是:

int (*p)(int,int);那么此时就是一个函数指针

只需要再给这个函数指针,附上一个地址,那么此时就是函数指针变量了,

int (*p)(int,int) = &fx;

有&,那就一定有*

所以我们可以尝试使用*来解引用一下这个函数指针.

*p就是解引用,那么*p解引用出来就是fx这个函数,而我们正常使用fx这个函数是fx(参数),所以:

(*p)(参数)就可以调用这个函数了.

(补充:(*p)将*p用括号包起来,是因为括号优先级比*高,所以如果不用括号抱起来,就会使后面的括号先进行,那么结果就会是:这个函数调用后,返回的结果,再使用*解引用了)

调用:

那么,我们上面说了,所以还知道:函数名 == &函数名 | 所以我们改成: int (*p)(int, int) = fx;

我们还知道p是指向fx的指针

所以p == fx ==&fx

所以我们还可以将(*p)(1, 2)中的(*p)改为p

也就是p(1, 2)

所以再给函数指针解引用时,*可以省略

无论多少个*都会省略

==============================================================

以上是初步了解函数指针,接下来,下面的内容则是深入了解.

==============================================================

(*(void (*)())0)()

(*(void (*)())0)()中,将(void (*)()去掉,就是(*0)(),在这里,0就很难理解,其实在这里0是地址,0x00000000

这里0也可以是别的地址,如:0x11223344

所以这里就是将0这个地址进行*解引用,然后调用这个函数

此时我们可以发现,0处的地址不一定是一个函数,可是从(*0)()这里又知道,因为有(),所以这里一定是函数,所以为了保证0处是函数,所以需要给0进行强制类型转换,转换成函数指针类型

所以这里的void (*)()就是函数指针类型,这与数组指针类型类似:void (*)[]

因此最后得到了:(*(void (*)())0)()

②void(*signal(int,void (*)(int,int)))(int)

这里又可以把,中间的:signal(int,void (*)(int,int))去掉看看,得到了void(*)(int),所以这又是函数指针类型.

那么可以讨论一下signal(int,void (*)(int,int)),signal是一个函数,用于警报的一个C语言函数。

其中signal有两个参数:

  1. int类型

  1. 函数指针类型

因为signal函数前面有个*,所以返回的是一个指针(函数指针)

所以,有一个signal的函数,参数一个是int类型,一个是函数指针类型,这个函数返回的是一个指针,这个指针也是函数指针。

为了方便理解,可以这样看这个函数(ps:只是方便理解,不能这样书写!)

我们可以用typedef定义类型

那么为什么把名字写在(*)里呢?

我们知道,定义函数指针变量和数组指针变量的时候是:

  1. int (*p)();

  1. int (*p)[];

我们知道,变量名都是写在(*)里面

正常定义整形类型,就是:int p;

所以如上图所示,在定义函数指针变量和数组指针变量的时候,都是在(*)里定义

如果要理解起来就是:int (*)() p ; 只是将p写到了(*)里

回归正题,我们定义了函数指针变量为pfx,为了方便理解void(*signal(int,void (*)(int,int)))(int)

完全可以将void(*signal(int,void (*)(int,int)))(int) 改变为:

此时我们就可以很好地理解这个函数了

PS:函数定义的时候,可以不需要参数名!

二.函数指针数组

了解完了函数指针,来看看函数指针数组。我们知道数组指针数组是int (*arr[5])[5],因此我们可以推出,函数指针数组是int (*arr[5])(int)。

函数指针数组的实际应用:

116. 指针进阶_哔哩哔哩_bilibili

三.函数指针数组的地址

函数指针数组的地址,我们应该怎么取出来呢?放在什么样的变量里呢?

想要得到 函数指针数组的地址 我们肯定需要定义函数,函数指针和函数指针数组

函数: ①int t1(int) ②int t2(int) ③int t3(int)

函数指针:①int (*p1)(int) = &t1 ②int (*p2)(int) = &t2 ③int (*p3)(int) = &t3

函数指针数组:int (*pa[3])(int) = {p1,p2,p3}

函数指针数组的地址,我们知道他是一个数组的地址也就是数组指针,类型是函数指针类型

所以我们可以创建一个数组指针,而数组指针对应的数组是有三个元素:int (*arr)[3]

我们还知道,他是一个函数指针类型,所以得到了:int (*(*arr)[3])(int)

如果有错,希望纠错!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

srhqwe

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

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

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

打赏作者

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

抵扣说明:

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

余额充值