定义一个二维数组a[10][5]:
#include <stdio.h>
#include <math.h>
int main()
{
char a[100][100];
printf("%d\n", &a[0][0]);
printf("%d\n", &a[5][5]);
return 0;
}
运行结果为:
因为是char数组,单个元素占1个字节,两者相减,易得a[5][5]的起始地址比a[0][0]高505个字节。
由此,可以得出二维数组的元素a[5][5]的起始地址的计算公式:
ADDRESS( a[5][5] )= A + ( 5 * 100 + 5 )* 1
那么通用公式就是,对于数组 a[ m ][ n ] 中的元素 a[ i ][ j ] 有:
ADDRESS( a[ i ][ j ] )= A + ( i * n + j )* sizeof(int)
其中A是数组a[0][0]的起始地址,也就是数组a的首地址。
简单解释一下:因为数组的坐标都是从0开始计算的,所以元素 a[ i ][ j ]前面有0到 i - 1行(也就是共 i 行)是完整的一行,可以直接乘以列数 n ,然后元素所在行(也就是 i 行)有0到 j - 1个元素,直接加上就好了。最后再乘以字节,加上首地址。
有人可能问你为什么不算到元素本身。你可以这样想,因为你已经算了a[0][0]的大小了,假如你想得到a[0][1]的起始地址,你直接拿a[0][0]的字节大小加上数组的首地址不就得了。所以,计算元素的地址,算到它前一个就够了,因为要的是元素的起始地址嘛!
上面说的是最常用的按行为主序存储的二维数组,要是按列为主序存储咋办?
因为数组是连续存储元素的,是在你不管咋个存储,每个元素都是前后元素挨着的,这个逻辑顺序不会变。
对于行列相等的二维数组,将 i 和 j 互换就可以保证地址不变的情况下,得到两种主序存储的元素坐标。也即:&a[ i ][ j ] (行主序) == &a[ j ][ i ](列主序)
对于行列不相等的二维数组,按照以下公式:
ADDRESS( a[ i ][ j ] )= A + ( j * n + i )* sizeof(int)
也就是把上面的公式 i 和 j 互换了一下。
如果已知按行主序的元素坐标,先求出其地址,然后代入上面的式子,就能得出按列主序的元素坐标了。至于你问我一个式子咋求俩未知数,我只能说, i 和 j 都有最大值限制,从这一点上规定了 i 和 j 的值是唯一值。
举个例子:
对于字符型二维数组a[10][8],首地址是1000,有按行为主序的元素a[4][7],通过求出它的地址然后求出按列为主序时,该地址对应的元素是哪个?
元素地址A = 1000 + ( 4 * 8 + 7 ) * 1 = 1039 = 1000 + ( j * 10 + i ) * 1
得出i = 9, j = 3,即a[9][3],不信用excel比划比划试试。