在C中,我知道我可以使用以下代码在堆上动态分配一个二维数组:
int** someNumbers = malloc(arrayRows*sizeof(int*));
for (i = 0; i < arrayRows; i++) {
someNumbers[i] = malloc(arrayColumns*sizeof(int));
}
显然,这实际上创建了一个一维数组的指针,指向一组单独的一维整数数组,“系统”可以找出我的意思,当我问:
someNumbers[4][2];
但是当我静态地声明一个2D数组时,如下所示…:
int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];
...是否在堆栈上创建了类似的结构,或者它完全是另一种形式?(例如,它是指针的1D数组吗?如果不是,它是什么,它的引用是如何被计算出来的?)
还有,当我说“系统”的时候,实际上是什么负责解决这个问题呢?内核?或者C编译器在编译时将其排序?
假设,我们有a1和a2的定义和初始化如下(c99):
int a1[2][2] = {{142,143}, {144,145}};
int **a2 = (int* []){ (int []){242,243}, (int []){244,245} };
a1是一个在内存中具有普通连续布局的同构二维数组,表达式(int*)a1被求值为指向其第一个元素的指针:
a1 --> 142 143 144 145
a2从一个异构的2D数组初始化,是一个指向int*类型值的指针,即解引用表达式*a2计算为int*类型值,内存布局不必是连续的:
a2 --> p1 p2
...
p1 --> 242 243
...
p2 --> 244 245
尽管完全不同的内存布局和访问语义,c语言的数组访问表达式语法对于同质和异构的2D数组看起来完全相同:
表达式a1[1][0]将从a1数组中获取值144
表达式a2[1][0]将从a2数组中获取值244
编译器知道a1的访问表达式操作int类型[2][2],而a2的访问表达式操作int类型**。生成的程序集代码将遵循同构或异构访问语义。
当类型为int[N][M]的数组被类型转换并以int**类型访问时,代码通常会在运行时崩溃,例如:
((int**)a1)[1][0] //crash on dereference of a value of type 'int'
答案是基于这样一个想法,即C并没有真正的2D数组——它只有数组的数组。当你宣布:
int someNumbers[4][2];
您要求someNumbers是一个包含4个元素的数组,其中该数组的每个元素的类型为int[2](它本身是一个包含2个int的数组)。
这个难题的另一部分是数组总是在内存中连续地布局。如果你问:
sometype_t array[4];
那么它总是这样的:
| sometype_t | sometype_t | sometype_t | sometype_t |
(4个sometype_t对象彼此相邻,中间没有空格)。在你的someNumbers数组中,它看起来是这样的:
| int [2] | int [2] | int [2] | int [2] |
每个int[2]元素本身就是一个数组,它看起来像这样:
| int | int |
总的来说,你得到了这个:
| int | int | int | int | int | int | int | int |
unsigned char MultiArray[5][2]={{0,1},{2,3},{4,5},{6,7},{8,9}};
在内存中等于:
unsigned char SingleArray[10]={0,1,2,3,4,5,6,7,8,9};
假设,我们有a1和a2的定义和初始化如下(c99):
int a1[2][2] = {{142,143}, {144,145}};
int **a2 = (int* []){ (int []){242,243}, (int []){244,245} };
a1是一个在内存中具有普通连续布局的同构二维数组,表达式(int*)a1被求值为指向其第一个元素的指针:
a1 --> 142 143 144 145
a2从一个异构的2D数组初始化,是一个指向int*类型值的指针,即解引用表达式*a2计算为int*类型值,内存布局不必是连续的:
a2 --> p1 p2
...
p1 --> 242 243
...
p2 --> 244 245
尽管完全不同的内存布局和访问语义,c语言的数组访问表达式语法对于同质和异构的2D数组看起来完全相同:
表达式a1[1][0]将从a1数组中获取值144
表达式a2[1][0]将从a2数组中获取值244
编译器知道a1的访问表达式操作int类型[2][2],而a2的访问表达式操作int类型**。生成的程序集代码将遵循同构或异构访问语义。
当类型为int[N][M]的数组被类型转换并以int**类型访问时,代码通常会在运行时崩溃,例如:
((int**)a1)[1][0] //crash on dereference of a value of type 'int'
要访问一个特定的2D数组,请考虑数组声明的内存映射,如下所示:
0 1
a[0]0 1
a[1]2 3
要访问每个元素,只需将感兴趣的数组作为参数传递给函数就足够了。然后使用offset for column分别访问每个元素。
int a[2][2] ={{0,1},{2,3}};
void f1(int *ptr);
void f1(int *ptr)
{
int a=0;
int b=0;
a=ptr[0];
b=ptr[1];
printf("%d\n",a);
printf("%d\n",b);
}
int main()
{
f1(a[0]);
f1(a[1]);
return 0;
}