笔试中返回函数指针数组的函数(超详解,从零开始)

前言

先看一段有趣的函数声明及引用:

//函数声明

void(***party(void (*p[2][2])(const char* name),const char* name))(const char* name)

//函数调用

party(p,"张三")[1][1]("李四");

我们当然不建议大家写这种复杂类型的函数声明,但由于它常成为笔试的重难点,而且分析这种复杂类型的代码对我们理解声明也有很大帮助。

一.理清“四要素”和操作符的优先性

1.四要素

为什么是四个呢?常调试的小伙伴应该知道监视窗口有名称,值,类型三个要素,有时也会调用内存窗口,故完整来说应该是四个。 

2.操作符的优先性 

在《C陷阱与缺陷》中这么提到:任何C变量的声明都是由两部分组成:类型以及一组类似表达式的声明符。声明符从表面上看与表达式有些类似,对他求值应该返回一个声明中给定类型的结果。(去掉声明符就是类型)

但其实还应该包含操作符,如:

void (*fp)();

fq是声明符,void(*)()是给定的返回类型,计算机的读取顺序其实还取决于操作符的优先性,我们接下来只需记住,优先级顺序() >  []  >   *  。

除此以外 

因为fp是一个函数指针,那么*fp就是该指针所指向的函数,所以(*fp)()就是调用该数的ANSICfp(),是一记住这种写法只是一种简写形式。

(*fp)0*fp括号数运算符()的优高于单运算符*。如果*fp*p()上与*(fp()的含一致,ANSIC把它*((*fp)())写形

 二.基础分析

1.指针数组与数组指针

int *p[3];
int (*p)[3];

 第一行是指针数组:p先跟 [] 结合,说明p是一个元素个数为3数组,再与 * 结合,说明数组中存放的是指针,最后与int结合,说明存放的指针指向的是int类型的(p的类型是 int*[3] )就p而言,p是存放3个int*数据的数组

第二行是数组指针:p先跟 * 结合,说明p是一个指针,再与 [] 结合,说明指针指向一个元素个数为3数组,最后与int结合,说明数组里存放的是int类型的。(p的类型是是 int[3] * )就p而言,p是一个指向存放3个int类型数据的指针。

2.指针函数与函数指针 

int * pf(int a, int b);
int (*pf)(int a, int b);

 第一行是指针函数,pf首先与()结合,说明他是一个函数,参数是有两个且都是int类型的,再与*结合,说明返回一个指针,最后与int结合,说明返回的指针指向一个int的数据(函数返回的是int*的数据)(pf的类型是int *(int,int) ) 就pf而言,他是一个参数为两个int数据,返回值为指向int数据的指针(int*)

第二行是函数指针,pf首先与 * 结合,说明pf是一个指针,再与()结合,说明指针指向的是一个函数,且参数是两个int类型的数据,最后与int结合,说明指向函数的返回类型是int(pf的类型是int (*)(int,int) 就pf而言,他是一个指向一个参数为两个int类型数据,返回值是int类型的函数的指针。

3.深入理解二级指针 

int **p;

 p先与右边的*结合,说明p是一个指针,再与左边的*结合,说明p这个指针指向一个指针,最后与int结合,说明指向的这个指针指向一个int类型的数据(p的类型是int**)就p而言,p是一个指向int*类型的指针,

 三,进阶分析(来源于《C陷阱与缺陷》)

1.(*(void (*)())0)();

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

先看第一个括号内的第一个括号内的(void (*)()),由上我们知道这是一个类型,考虑到大家可能会反应不过来,就再分析一遍:

进来括号的优先级最高,先读 * ,说明这是一个指针,在于()结合,说明指针指向一个函数,再与void结合,说明指向的函数无返回类型(函数指针类型)

括起来后与右边的0结合说明将0强制转换成函数指针类型

与*结合说明0这个指向无参数无返回类型的函数指针指向另一个指针,再与括号结合说明指向的另一个指针是一个函数,整体是一个表达式,说明正在调用。

2. void (*signal(int , void(*)(int)))(int);

void (* signal(int , void(*)(int) ) )(int);

 signal首先与()结合,说明这是一个函数,

一个参数是int类型,另一个参数是void(*)(int)类型

再与*结合,说明返回类型是一个指针,再与()结合,说明返回的这个指针是一个函数,由一个参数,是int类型,最后与void结合,说明返回函数的返回无类型

即signal函数有两个参数,返回一个参数为int,返回无类型的函数指针。

四.回归前言问题 

void(***party(void (*p[2][2])(const char* name),const char* name))(const char* name)

party先与()结合说明这是一个函数,我们只需要明确party的参数及返回值,括号内自然是参数,然后与*结合,说明是返回一个指针该指针指向为void(**)(const char* name),至于该类型下面调用再讲

party(p,"张三")[1][1]("李四");

 party(p,"张三")看成一个表达式,最终会返回一个类型为void(**)(const char* name)的数据,两个[1]就是解引用这个函数数组,()便是函数调用的意思

最后,来一段代码

#include<stdio.h>

void zhufu1(const char* name)
{
	printf("%s:祝你在新的一年里身体健康,无病无灾,喜乐长,安宁久\n",name);
}
void zhufu2(const char* name)
{
	printf("%s:祝你在新的一年独占鳌头,龙游浅水、悠然自得,事业有成。\n", name);
}
void zhufu3(const char* name)
{
	printf("%s:祝你在新的一年里像龙一样勇往直前,无惧风浪,事业节节高,生活更美好\n", name);
}
void zhufu4(const char* name)
{
	printf("%s:祝你在龙年里,像龙一样拥有无比的力量和智慧,克服一切困难,迎接更加美好的明天!", name);
}
void (*p[4])(const char* name) = { zhufu1,zhufu2 , zhufu3, zhufu4};

void(**party(void (*p[4])(const char* name),const char* name))(const char* name)
{
	for (int i = 0; i < 4; i++)
	{
			p[i]("furina");
	}
	printf("\n");
	return p;
}

int main()
{
	party(p,"张三")[1]("李四");
	return 0;
}

 

 最后祝各位读者新年快乐

  • 42
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 19
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值