文章目录
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())()
首先, ()
的结合优先级最高
f
与()
结合, 说明这个类型是个返回值为xxx的函数- 我们把
f()
删去, 剩下的即为返回值类型:int (*)()
: 说明他的返回值是一个函数指针
基本类型如int 我就省略了诸如 元素类型为, 返回类型为xxx的描述了!
至此我们分析完毕
根据基本规律1: 声明删去标识符即为类型, 我们将f
删去
即int (*())()
的类型是: 一个返回函数指针的函数
例2: 分析返回函数指针的函数指针
//返回函数指针的函数指针
int (*(*f)())()
我们利用上面的公式继续分析:
(*f)
说明他是一个指针 , 但是这还不够(*f)
继续和优先级比较高的()
继续结合, 说明他是一个函数指针- 我们将
(*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)[])()
是的, 我只是做了一点改动:
- 说明中 返回值类型 改为 元素类型
- 将
()
改为[]
按照上面的步骤来!
相信你会得到答案
4 构造方法/公式
1. 先写出函数指针(函数)的返回值类型 或者 数组指针(数组)的元素类型
2. 在最里层的* 右边写
1. *函数: f()
2. *函数指针: (*f)()
3. *数组: arr[]
4. *数组指针: (*arr)[]
上面的步骤都是可以递归进行的
例1: 构造返回值为数组指针的的函数指针
首先, 数组指针是: int (*)[]
- 所以我们先写出返回值类型:
int (*)[]
- 因为是个函数指针, 我们再在 最里层的* 旁边写
(*f)()
- 得到:
int (* (*f)() )[]
例2: 构造元素类型为(返回值为数组指针的函数指针)的数组
同样的, 根据上面, 我们能写出返回值为数组指针的函数指针的类型: int (* (*)() )[]
- 所以我们先写出数组元素类型:
int (* (*)() )[]
- 因为是个数组, 我们再在 最里层的 * 旁边写
arr[]
- 得到:
int (* (*arr[])() )[]
我们可以测试一下下面这段代码!
//返回值为数字指针的函数
int (*faa())[]{
}
// 元素类型为(返回值为数组指针的函数指针)的数组
int (*(*arr[2])())[]={
faa,faa
};
请你尝试构造:
- 返回值为 (元素为函数指针的数组指针) 的函数指针
- 元素类型为(元素为函数指针的数组指针) 的数组指针
//返回值为 (元素为函数指针的数组指针) 的函数指针
int (*(*(*f2)() )())[];
//元素类型为(元素为函数指针的数组指针) 的数组指针
int (*(*(*f2)[] )())[];
5 总结
综上, 我们可以得出构造方法和分析方法大致步骤
- 构造:
- 写出返回值/元素 类型
- 根据变量类型来写其他剩余部分
- 分析:
- 分析出是什么变量
- 删除变量相关部分, 即为 返回值/元素 类型
上面的步骤都是可以递归进行的