深入浅出C指针(三)易做图数组
1.概念
如果某个数组的维数不止1个,它就被称为易做图数组。例如,下面这个声明:
int matrix[6][10];
创建了一个包含60个元素的矩阵。但是,它是6行每行10个元素,还是10行每行6个元素?
为了回答这个问题,你需要从一个不同的观点视察易做图数组。考虑下列这些维数不断增加的声明:
int a;
int b[10];
int c[6][10];
int d[3][6][10];
a和b很好理解。c只是在b的基础上在增加一维,所以我们把c看作是一个包含6个元素的向量,只不过他的每个元素本身又是一个包含10个元素的向量。换句话说,c是一个一维数组的一维数组。d也是如此:它本身是一个含有3个元素的向量,而这三个元素中每个元素本身又是一个含有6个元素的向量,而这6个元素各自本身又是一个含有10个元素的向量。
2.存储顺序
请记住,易做图数组只是表示上的一种写法,而在实际的内存空间存储中,还是按照顺序的存储方式。
例如:int[2][5];
在内存中是按顺序排列的10个小区域。
看看下面这个例子:
int matrix[6][10];
int *mp;
.....
mp = &matrix[3][8]
printf("First value is %d\n",*mp);
printf("Second value is %d\n",*++mp);
printf("Third value is %d\n",*++mp);
很显然,第一个被打印的值将是matrix[3][8]的内容,那下一个被打印的又是什么?顺序存储可以回答这个问题--下一个元素将是最右边下标首先变化的那个,也就是matrix[3][9]。再接下去又轮到谁呢?第9列已是最后一列。不过,按顺序存储的规定,一行存满后就轮到下一行,所以下一个被打印的元素将是matrix[4][0]。
2.数组名
一维数组的数组名是一个指针常量,这一点大家应该已经十分清楚了。它的类型是“指向元素类型的指针”,它指向数组元素的第一个元素。易做图数组也差不多,但是这个“差不多”往往会给初学者带来一定的误导,易做图数组的数组名,也是一个指针,这个指针指向的是该数组的第一个“元素”,这个“元素”也是一个数组。例如,下面这个声明:
int matrix[3][10];
接着看以下的表达式:
matrix[1][5]
这个很简单,该表达式表示这个数组的第二行,第六列所包含的元素。
matrix + 1
如果你认为这个表达式指向了第一行的第二个元素,那么你就错了。实际上,这个表达式指向的是第二行整个数组,而不是任何一个元素。www.zzzyk.com
而*(matrix + 1)是一个指向第二行第一个元素的指针。*(*(matrix + 1))表示了第二行第一个元素的具体值。
其实就笔者感觉,C语言易做图数组这样的设计方式不是十分恰当,这样做和一维数组的规则没有十分紧密的联系起来,就易于理解而言,matrix + 1表示第一行的第二个元素更为容易理解一些。不过可能是出于编码的简洁性考虑,C语言的发明人采用了这样“自动换行”的处理过程。
小提示:
在许多其他的语言,比如大家熟悉的C#中,多重下标被写成用逗号分割的形式。比如:
matrix[3,4];
如果你在C语言中这样写会发生什么呢?你的第一感觉一定是:编译错误。不过很可惜,C语言可以让这样的表达式编译通过(还记得2[array]吗?C语言的灵活性是其他语言所不能比拟的)。
这样看上去没有什么问题,实际这样的表达式运行结果一定会和你预想的结果不一样。
C语言的逗号表达式会将其转换成matrix[3]。
如果编译器可以发现这个错误还好,可惜由于逗号表达式的存在,编译器无法发现这样的错误。
3.指向数组的指针
下面这些声明合法吗?
int vector[10], *vp = vector;
int matrix[3][10], *mp = matrix;
第一个声明是合法的。它为一个整形数组分配内存,并把vp声明成一个指向整形的指针,并把它初始化指向vector数组的第一个元素。
第二个声明是非法的。它正确的创建了matrix数组,并把mp声明为一个指向整形的指针。但是,mp的初始化是不正确的,因为matrix并不是一个指向整形的指针,而是一个指向整形数组的指针。我们应该怎样声明一个指向整形数组的指针呢?
int (*p)[10];
这个声明略微复杂但却是正确的,在声明中加上初始化后是下面这个样子:
int (*p)[10] = matrix;
它使p指向matrix的第一行。
p是一个指向拥有10个整形元素的数组指针。当你把p与一个整数相加时,该整数首先根据10个整形的长度进行调整,然后再进行加法。所以我们可以使用这个指针一行一行地在matrix中移动。
如果你需要的是一个指针逐个访问整形元素而不是逐行在数组中移动,我们可以这样声明:
int *pi = &matrix[0][0];
int *pi = matrxi[0];
4.初始化
对易做图数组的初始化,一般有两种方式:
int matrix[2][3] = {100,101,102,103,104,105};
int matrix[2][3] = {
{100,101,102},
{103,104,105}
};
二者在本质上没有任何区别,只是第二种初始化的方式程序可读性更高一些。
摘自 Kernel & UI
补充:软件开发 , C语言 ,