多维数组那回事儿

2011年2月10日 由 edsionte 留言 »

前面几篇“那回事儿”的文章更强调一维组和指针之间的关系,本文关注的是多维数组,即“数组的数组”。

多维数组

我们可以将多维数组抽象的看作是具有某种类型的一维数组。当“某种类型”为基本的数据类型时,多维数组就退化成普通的一维数组;当“某种类型”仍然为数组时,那么就形成了多维数组。也就是说任何一个多维数组都可以分解成几个一维数组。

下面通过示例程序来深入了解多维数组ma[2][3]的构成。

#include < stdio.h >

int main()
{
	int ma[2][3];
	int (*r)[2][3];
	int (*p)[3];
	int *t;

	/*代码段1*/
	p = ma;
	printf("sizeof(ma[0])=%d\n",sizeof(ma[0]));
	printf("ma      =%p\tp   =%p\n",ma,p);
	printf("p+1 =%p\n",p+1);
	/*代码段2*/
	r = &ma;
	printf("sizeof(ma)=%d\n",sizeof(ma));
	printf("&ma     =%p\tr  =%p\n",&ma,r);
	printf("&ma+1   =%p\tr+1=%p\n",&ma+1,r+1);
	/*代码段3*/
	t = ma[0];
	printf("sizeof(ma[0][0])=%d\n",sizeof(ma[0][0]));
	printf("ma[0]   =%p\tt   =%p\n",ma[0],t);
	printf("ma[0]+1 =%p\tt+1 =%p\n",ma[0]+1,t+1);
	return 0;
}

由多维数组ma最左维的长度2可知,ma数组包含两个元素ma[0]和ma[1]。数组名ma在表达式中是数组ma首元素的首地址。在代码段1中将ma赋值给数组指针p,则p指向多维数组ma的首元素ma[0],则p+1指向第二个元素ma[1]。其中p是一个数组指针,它指向一个长度为3的数组,则指针p每次移动的偏移量为12。可参考下图:


在代码2中对ma取地址并将其赋值给指针r。r现在指向一个“第一维的大小为2,第二维的大小为3的数组”,则r+1将指向下一个这样的数组(尽管这样的数组并不存在)。由此也可得知r每次的偏移量为24。


ma[0]和ma[1]都是一个长度为3的整型数组,现在以ma[0]为例进行说明。ma[0]中包含三个元素ma[0][0],ma[0][1]和ma[0][2]。在代码段3中将ma[0]赋值给t,则t指向数组ma[0]的第一个元素a[0][0],则t+1和t+2则依次指向第二个元素和第三个元素。


对多维数组ma的结构有了一定了解后,现在再看上述程序的运行结果:

edsionte@edsionte-laptop:~/code/expertC$ gcc array.c -o array
edsionte@edsionte-laptop:~/code/expertC$ ./array
sizeof(ma[0])=12
ma   =0xbfdfaa6c	p=0xbfdfaa6c
p+1  =0xbfdfaa78
sizeof(ma)=24
&ma  =0xbfdfaa6c	r=0xbfdfaa6c
r+1  =0xbfdfaa84
sizeof(ma[0][0])=4
ma[0]=0xbfdfaa6c	t=0xbfdfaa6c
t+1  =0xbfdfaa70

注意在结果中,p,r和t的值均相同,但是所指向的数据却不同。更具体的说,这三个指针每次移动时的偏移量不同。

多维数组的初始化

数组的初始化只能在对数组进行声明(具体为定义型声明)时进行。一维数组的初始化很简单,只要将所有初始值放在一个大括号中即可。如果声明数组时未指定数组的长度,则编译器会根据初始值的个数来确定数组的长度。

#include < stdio.h >

int main()
{
	int m[] = {1,2,3};
	int n[] = {1,2,3,};

	printf("length(m)=%d\n",sizeof(m)/sizeof(m[0]));
	printf("length(n)=%d\n",sizeof(n)/sizeof(n[0]));
	return 0;
}

/* 编译并运行 */
edsionte@edsionte-laptop:~/code/expertC$ gcc init_array.c -o init_array
edsionte@edsionte-laptop:~/code/expertC$ ./init_array
length(m)=3
length(n)=3

注意,在最后一个初始值后面可以继续加一个逗号也可以省略,这并不影响数组的长度。

对于多维数组而言,通常使用嵌套的大括号进行多维数组的初始化。由于多维的数组其实是有若干个一维数组构成的,则每个大括号都代表一个一维数组。对于多维数组而言只能省略最左边 下标的长度。

#include < stdio.h >

int main()
{
	int b[][3] = {1,2,1,1};
	int c[][3] = {{1,2,1},{1,2,3},};

	printf("length(b)=%d\n",sizeof(b)/sizeof(b[0]));
	printf("length(c)=%d\n",sizeof(c)/sizeof(c[0]));
	return 0;
}

/* 编译并运行 */
edsionte@edsionte-laptop:~/code/expertC$ gcc init_array.c -o init_array
edsionte@edsionte-laptop:~/code/expertC$ ./init_array
length(b)=2
length(c)=2

可以看到,不使用大括号也可以对多维数组进行初始化,只不过代码可读性较差。

它总是迷惑你!

一旦涉及到多维数组,总有些让你迷惑的地方。比如:

	char ma[2][3][2]={
		{{1,2},{2,3},{3,4}},
		{{3,5},{4,5},{3,3}}
	};

sizeof(ma[0,1,1])=?

对于上面的代码,我们最后的迷惑点都可能落在ma[0,1,1]上。难道多维数组可以这样使用吗?如果ma[0,1,1]和ma[0][1][1]等价,那么sizeof(ma[0,1,1])的值就是1。很可惜这样的猜测是不正确的,正确答案为6。再比如下面的代码:

		char ma[3][2] = {
		(1,2),(3,4),(5,3)
	};

ma[0][0]=?

上述代码是为数组ma进行初始化,那么ma[0][0]的值是多少?恐怕很多人都会认为是1。不过正确答案是2。

这两个问题都涉及到了逗号表达式。如果你对逗号表达式有基本的了解,那么也就没有上述那种莫名其妙的迷惑了。根据逗号表达式的运算,对于举例1中的ma[0,1,1]实际上等价于ma[1];对于举例2中的初始化其实等价为char ma[3][2] = {2,4,3}。

参考:

《C专家编程》 人民邮电出版社;(美)林登(LinDen.P.V.D) 著,徐波 译;

 

广告位

发表评论

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key