一文让你彻底搞懂C语言的复杂函数,指针和数组的分析方法,构造方法 | C语言任意类型构造与分析方法万能公式 | C语言高级-函数,数组与指针

1 为什么你应该看这篇文章?

1. 1 你能看懂下面几个类型吗?

在你看这篇文章之前, 请你先看看下面的几个类型.(为了不浪费大家的时间)
如果你能看懂的话, 当然你可以肆意浏览一下这篇文章, 但如果你一头雾水的话, 你应该好好阅读一下这篇文章!

//例1: 元素类型是函数指针的数组指针
int (* (*foo4)[])()  ;

//例2: 返回值是(返回值为数组指针的函数指针)的函数  
int (*(*foo5())())[];

//例3: 元素类型是(返回值为数组指针的函数指针)的数组  
int (*(*foo5[])())[];

你可能觉得, 我从来不需要去写这么复杂的句式, 那么你不妨看看下面这个STL中的活生生的例子

1.2 STL中的例子

来看看STL中的一段返回值为函数指针的函数

 static void (* __set_malloc_handler(void (*__f)()))()
  {
    void (* __old)() = __malloc_alloc_oom_handler;
    __malloc_alloc_oom_handler = __f;
    return(__old);
  }

2 几条基本规律/原则:

要说明这个构造方法前,我们要先说明一下C语言中类型的几个基本规律/原则

2.1 声明删去变量标识符即为类型

不管多么复杂的的类型, 都是可以从声明删去变量得到的, 下面以函数指针数组指针为例:

//函数指针的声明
int (*p)();

据上, 我们删去 p函数指针类型即为: int (*)() , 同理, 数组指针的类型为 int (*)[]

2.2 函数的返回值类型与数组的元素类型具有相同地位

还是以函数指针和数组指针为例:
说明:如果我们从返回值为int的函数指针转变到元素类型为int的数组指针时,我们只改变了 ()=>[] , 就完成了这个转变, 而无需对返回值类型(数组的元素类型)做出相应的改动, 因此说函数的返回值类型与数组的元素类型具有相同地位

//函数指针
int (*p)();
//数组指针
int (*p)[];

当然也能看一个复杂点的例子

//例2: 返回值是(返回值为数组指针的函数指针)的函数  
int (*(*foo5())())[];

//例3: 元素类型是(返回值为数组指针的函数指针)的数组  
int (*(*foo5[])())[];

看上面两个例子, 我们只改变了 () => [] !
怎么样,有点感觉了把

2.3 函数的参数与数组的元素个数总是能轻易看出

继续以函数指针为例
说明: 事实上, 函数(指针)参数, 数组(指针)的元素个数, 总是紧跟着标识符的, 因此他总能被能轻易看出

//函数指针: 参数为int ,double
int (*p)(int, ouble);
//数组指针: 元素个数为4个
int (*p)[4];

当然我们可以再以例3, 例2为例
可以看到, 为了添加参数, 我门只是在标识符旁边或旁边的括号加了个 int, 或者是元素个数4

//例2: 返回值是(返回值为数组指针的函数指针)的函数: 无参数
int (*(*foo5())())[];

//例2改: 返回值是(返回值为数组指针的函数指针)的函数: 参数为int
int (*(*foo5(int))())[];

//例3改: 元素类型是(返回值为数组指针的函数指针)的数组: 参数为4
int (*(*foo5[4])())[];

3 分析方法/公式

1. 先看最深层次中符号的结合度  ()[]* ,()结合为函数,[] 结合为数组,*结合为指针
	1. p(xxx)/*p(xxx) ->	 函数 , xxx中为参数
	2. (*p)()-> 函数指针
	3. p[4]/*p[4] ->数组
	4. (*p)[4] -> 数组指针
3. 把标识符和1 中所结合的符号删去,剩下的类型即为 数组元素类型 或者函数返回值  

上面的步骤都是可以递归进行的

例1: 分析返回函数指针的函数

下面是一个返回函数指针的函数, 我们可以利用刚刚的方法来分析他

//分析返回函数指针的函数
int (*f())()

首先, ()的结合优先级最高

  1. f() 结合, 说明这个类型是个返回值为xxx的函数
  2. 我们把f() 删去, 剩下的即为返回值类型: int (*)() : 说明他的返回值是一个函数指针

基本类型如int 我就省略了诸如 元素类型为, 返回类型为xxx的描述了!

至此我们分析完毕
根据基本规律1: 声明删去标识符即为类型, 我们将f删去
int (*())()的类型是: 一个返回函数指针的函数

例2: 分析返回函数指针的函数指针

//返回函数指针的函数指针
int (*(*f)())()

我们利用上面的公式继续分析:

  1. (*f) 说明他是一个指针 , 但是这还不够 (*f) 继续和优先级比较高的()继续结合, 说明他是一个函数指针
  2. 我们将(*f)()删去 得到 返回值类型 int (*) () , 所以他是一个返回函数指针的函数指针

所以:
int (*(*f)())() 是一个返回函数指针的函数指针

例3:返回数组的二级指针的函数

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

你可能会发现在去掉 pa(int)后 , 只剩下了

int (*(* ))[3] ;

可能你会看不懂这是什么
实际上, 这里的括号是多余的!我们把它去掉再来看看

int (**) [3]

是的他是一个数组的二级指针

int (**p(int))[3] {
	
	int a[3] = { 0, 0 ,0 };
	int (*b)[3] = &a;
	
	return &b; 
}

请你尝试分析

下面请你分析:

//元素类型为函数指针的数组
int (*fa[4])();
//元素类型为函数指针的数组指针
int (*(*fap)[])()

是的, 我只是做了一点改动:

  1. 说明中 返回值类型 改为 元素类型
  2. () 改为 []

按照上面的步骤来!
相信你会得到答案

4 构造方法/公式

1. 先写出函数指针(函数)的返回值类型 或者 数组指针(数组)的元素类型
2. 在最里层的* 右边写
	1. *函数: f()
	2. *函数指针: (*f)()
	3. *数组: arr[]
	4. *数组指针: (*arr)[]

上面的步骤都是可以递归进行的

例1: 构造返回值为数组指针的的函数指针

首先, 数组指针是: int (*)[]

  1. 所以我们先写出返回值类型: int (*)[]
  2. 因为是个函数指针, 我们再在 最里层的* 旁边写 (*f)()
  3. 得到: int (* (*f)() )[]

例2: 构造元素类型为(返回值为数组指针的函数指针)的数组

同样的, 根据上面, 我们能写出返回值为数组指针的函数指针的类型: int (* (*)() )[]

  1. 所以我们先写出数组元素类型: int (* (*)() )[]
  2. 因为是个数组, 我们再在 最里层的 * 旁边写 arr[]
  3. 得到: int (* (*arr[])() )[]

我们可以测试一下下面这段代码!

 //返回值为数字指针的函数
 int (*faa())[]{
  } 
  // 元素类型为(返回值为数组指针的函数指针)的数组 
 int (*(*arr[2])())[]={
	faa,faa
  };

请你尝试构造:

  1. 返回值为 (元素为函数指针的数组指针) 的函数指针
  2. 元素类型为(元素为函数指针的数组指针) 的数组指针
//返回值为    (元素为函数指针的数组指针) 的函数指针
int (*(*(*f2)() )())[]; 
//元素类型为(元素为函数指针的数组指针) 的数组指针
int (*(*(*f2)[] )())[]; 

5 总结

综上, 我们可以得出构造方法和分析方法大致步骤

  1. 构造:
    1. 写出返回值/元素 类型
    2. 根据变量类型来写其他剩余部分
  2. 分析:
    1. 分析出是什么变量
    2. 删除变量相关部分, 即为 返回值/元素 类型

上面的步骤都是可以递归进行的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值