1、float(**a)[5];
2、double*(*a)[5];
3、double(*a[5])();
4、int*((*a)[5]);
5、long(*a)(int);
6、int(*(*a)(int))(int,int);
好吧如果你能准确说出来上面所有六个声明a的意义,就不用往下看了,只要留言告诉我你用什么方法就好了。如果你说不出来,那我就说说我的方法,不一定好,但是起码能认出来;
一、简单声明:
1、T a; //声明一个T类型的变量a
2、T a[5]; //声明一个数组a,其元素类型为T
3、T *a; //声明一个T类型的指针a
4、T **a; //声明一个指向指针的指针
5、T(*a)(A); //声明一个函数指针,参数类型为A,返回值类型为T;
二、混合类型的产生:
我将一个完整的声明分为三部分:
1、类型部分:就是上面的T,对不同的声明来说T的意义也不同,比如对数组而言,T是元素的类型,对一般指针T是其指向类型,对函数指针来说T是指向函数的返回类型;
2、核心部分:就是上面的a,对简单声明来说这部分只是一个名字,单独提取出来没有任何意义,但是对于混合声明而言,这部分往往是另外一个完整的声明;
3、描述部分:除了T和a以外的操作符,描述说明a的本质到底是指针、数组等等;
混合声明本质就是将一个简单声明的核心部分合理的替换成另外一个简单声明。所谓合理的就是满足一些基本原则,比如数组不能作为函数返回值等。
三、混合声明的写法:
如何写出一个纠结的混合声明?我想出了一种有效的方法,形象的命名为“装箱子”法:
1、先找到声明的本质,然后写出一个完整的简单声明,类型部分如果暂时无法给出简单的用写为T,如果给出则完成;
2、再写出外层声明,并将核心部分替换为,已经完成的明核心部分与描述部分。就像装进箱子一样,最好加上();
3、继续2,直到外层写完,类型已知为止。
举例说明:
1、写一个函数指针a,参数分别为int和double,返回一个指向char类型的指针:
分析上面要求,a的本质是一个函数指针。根据步骤1写出它的简单声明 T (*a)(int,double);
写出外层声明,一个char类型的指针 char *b;
装箱 b替换为 (*a)(int,double) 结果为 char *( (*a)(int,double) );
在装箱过程中有些括号是没有必要的,但为了便于理解或可以去掉些,或最好保留;
2、写一个指向长度为5的一维数组的指针,数组元素为返回值是char,参数为int类型的函数指针:
本质为指针 T *a;
外层T为指向类型,一个长度为5的一维数组 T b[5]; 装箱 T (*a)[5];
再外层T为数组元素类型,一个函数指针 char (*c)(int); 装箱 char (* ((*a)[5]) )(int);
四、混合声明的读法:
比起写法来说,用更多的是读法。谁没事闲的写这么纠结的类型声明,但是要是有人写了就应该能读出来。读的方法自然是写法的逆向过程:
1、先找到名,看看到底是个什么东西,如果名右面已经是)就要看左边了一些根据优先级相关的原则 *a[5] 先想到a是个数组、同理*a()先想到a是个函数;
2、看外层,外层将作为核心部分的类型部分存在,核心部分不同,对应作为类型部分的外层意义也不同;
3、继续2直到完全读出。
现在来看上面的6个声明:
1、float(**a)[5];
a是一个指针的指针,所指向的指针,指向一个数组,数组元素类型为float;
2、double*(*a)[5];
a是个指针,指向一个数组,数组元素类型为指向double类型的指针;
3、double(*a[5])();
a是一个数组,元素类型是一个函数指针,指向没有参数,返回类型为double类型的函数;
4、int*((*a)[5]);
a是一个指针,指向一个数组,数组的元素类型为指向int类型的指针;
5、long(*a)(int);
a是一个函数指针,指向一个没有参数,返回值为long类的函数;
6、int(*(*a)(int))(int,int);
a是一个函数指针,指向函数的参数为int,返回值为一个函数指针,这个函数指针所指向的函数参数为两个int返回值是int。