Assembly 多维数组

2018-10-29 14:56 更新

多维数组和已经讨论的普遍的一维数组相比,差异并不是很大。事实上,在内存中,它们的描述方法和普遍的一维数组是一样的。

二维数组

不要感到意外,最简单的多维数组就是二维数组。一个二维数组通常以网格的形式来表示元素。每个元素通过两个下标来确定。按照惯例,第一个下标用来确定元素的行值,而第二下标用来确定元素的列值。

考虑一个三行二列的数组,像这样定义:

int a [3][2];

C编译器将为这个数组保留6(= 2 X 3)个整形数的空间,而且像下面一样来映射元素:

映射元素

这张表试图展示的是a[0][0]引用的元素储存在6个元素的一维数组的开始。元素a[0][1]储存在下一个位置(下标1),以此类推。在内存中,二维数组的各个行都是连续储存的。一行的最后一个元素后面紧跟着下一行的第一个元素。这就是所谓的数组依行表示法,这也是C/C++编译器表示数组的表示方法。

在依行表示法中,编译器如何确定a[i][j]出现在哪?一个简单的公式将通过i和j来计算下标。在这个例子中,公式为2i + j。并不难看出如何得到这个公式。每一行有两个元素大小;所以行i的第一个元素的位置为2i。然后该行的j列的位置可以通过j和2i相加得到。这个分析同样展示了如何产生N列数组的公式:N X i + j。注意,这个公式并不依赖于行的总数。作为一个例子,我们来看看gcc如何编译下面的代码(使用上面定义的数组a):

x = a[i ][ j ];

x = a[i ][ j ]


图5.6展示了这条语句翻译成的汇编语言。因此编译器实质上将代码转换成:

x = *(&a[0][0] + 2*i + j );

而且事实上,程序员可以以这种方法来书写,也可以得到同样的结果。

选择依行的数组表示法并没有什么魔力。依列的表示法同样可以工作:

元素

在依列表示法中,各列被连续储存。元素[i][j]储存在i + 3j位置中。其它语言(例如:FORTRAN)使用依列表示法。当与多种语言进行代码接口时,这是非常重要的。

大于二维

对于大于二维的数组,应用了同样原理的想法。考虑一个三维数组:

int b [4][3][2];

在内存中,这个数组将被当作四个大小为[3][2]的二维数组被连续储存。

下面的表展示了它如何运作:

大于二维的数组

计算b[i][j][k]的位置的公式是6i + 2j + k。其中6由[3][2]数组的大小决定。一般来说,对于维数为a[L][M][N]的数组,元素a[i][j][k]的位置将是M £ N £ i + N £ j + k。再次需要注意的是,第一个维的元素个数(L)并没有出现在公式中。

对于更高维的数组,可以通过推广来做同样的处理。对于一个从D1到Dn的n数组,下标为i1到in的元素的位置可以由下面这个公式得到:

D1到Dn的n数组

或者对于超级的数学技客,它可以用更简洁地书写为:

公式

第一维D1,并没有出现在公式中。

对于依列表示法,普遍的公式将是:

公式2

在这种情况下,是最后一维Dn,不出现在公式中。

在C语言中,传递多维数组参数

多维数组的依列表示法在C编程有一个直接的效果。对于一维的数组,当任何具体的元素被放置到内存中时,数组的大小并不需要计算出来。但这对于多维数组是不正确的。为了访问这些数组的元素,除了第一维的元素个数,编译器必须知道其它所有维数的元素个数。当一个函数的原型带有一个多维数组参数时,这就变得很明显了。下面的代码将不会被编译:

void f ( int a[ ][ ] ); /* 没有维数信息 */

但是,下面的代码就会被编译:

void f ( int a[ ][2] );

任何有两列的二维数组可以传递给这个函数。第一维的元素个数是不需要的。

不要被这类函数的原型搞混了:

void f ( int * a[ ] );

它定义了一个一维的整形指针数组。(它可以附带用来创建一个像二维数组一样运作的数组。)

对于更高维的数组,除了第一维的元素个数,数组参数的其它维数的必须指定。例如,一个四维的数组参数可以像这样被传递:

void f ( int a[ ][4][3][2] );


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号