问题:给定7个4*4的数组,需要定义一个包含7个元素的数组,数组的每个元素是这7个数组的首地址,并且不能用如
int p[7][4][4] = {
7个数组的定义....
};
而是,假设已经有了7个数组的定义在前,要把这7个数组的首地址存放在一个相当于地址表的数组里面以便映射之用.
解决的方法有最简单的一种,不过不推荐使用,就是直接把地址表数组定义成为void*型,强制转换的任务交给编译器做.
一劳永逸的办法就是趁这个机会补一补BT的C语言中声明的语法规则,在<>中有这么一段:
理解c语言声明的优先级规则:
1) 声明从它的名字开始读取,然后按照优先级顺序依次读取
2) 优先级地从高到低的顺序是
a)声明中括号被括起来的部分
b)后缀操作符:
括号()表示这是一个函数,方括号表示这是一个数组
c)前缀操作符,*表示这是一个指针
3)如果有const或volatile后面紧跟类型说明符如int等,那么它作用于类型说明符,在其它情况下,const等作用于紧邻的指针星号
回到问题中来,假设下面要用到的sheet1~sheet7都是int [4][4]型的数组,那么可以这么做:
typedef int (*ptr)[4][4];(注意不要写成typedef (int *ptr)[4][4];了)
定义了一个新类型,根据上面的三条准则可以这么理解:首先读括号里的,ptr是个int型的指针,然后后面有后缀符[],因此ptr是个指向4*4数组的指针.
这样以后就可以这样用了:
ptr p[7] = {
&Sheet1, &Sheet2, &Sheet3,
&Sheet4, &Sheet5, &Sheet6, &Sheet7
};
如果已经理解了上面的规则,也可以不用typedef,直接这样写:
int ((*p[7])[4][4]) = { /* 注意不要写成(int *p[7])[4][4];了 */
&Sheet1, &Sheet2, &Sheet3,
&Sheet4, &Sheet5, &Sheet6, &Sheet7
};
依次读下来就是:p是一个包含7个元素的数组,因为前面有*号,可以因此括号中的部分可以理解为p是一个包含7个指针的数组;指针的指向是什么?在上一层括号中有了答案:指针指向的是int型的4*4数组(呵呵,我也差点胡涂了...)
以上即是如何理解c中BT的声明语法的准则和例子,但愿已经说清楚了.
btw1:上面的数组初始化中如果4*4数组名前没有&号,那么在c中可以编译过去但是会出现警告(我用的gcc),但是在c++中就过不去了(g++),提示是"error: cannot convert `int (*)[4]' to `int (*)[4][4]' in initialization",也就是说它把sheet1的数组名看作是int (*)[4]了,而加上&号以后就把数组名看作是一个二级指针了,由此可以看出c和c++在处理类型时的一些分别来.
btw2:在通过数组p来访问4*4数组中的元素时,注意到p是一个指针因此在取元素之前要解指针引用,如(*p[0])[0][0],如果漏掉前面的解引用如p[0][0][0]那么就是把p当作是3维数组使用了,后果可想而知.....
btw3:如果一时之间无法识别指针的类型,还有一个笨方法,使用gdb,比如对sheet1,我在gdb中输入"p &sheet1",就是打印出变量sheet1的地址,此时gdb会同时打印出这个变量的类型,这里是:int (*)[4][4],注意到中间的*说明了这个类型是个指针,因此在*号旁边加入我们想要的就可以了,比如在这里是int (*p[7])[4][4],因此我们还可以这样写typedef:
typedef int (*ptr[7])[4][4];(注意不要写成typedef (int *ptr[7])[4][4];了)
ptr p = {
&Sheet1, &Sheet2, &Sheet3,
&Sheet4, &Sheet5, &Sheet6, &Sheet7
};
结语:很多时候我们并不这样写程序,不过多了解一点还是好的,通过这个例子,又加深了我对声明,指针的理解.
理解c中复杂的声明语法

最新推荐文章于 2024-01-28 19:56:34 发布
