注意:本文中所使用的示例仅用于解释概念。因此,示例可能不完整,可能缺乏错误处理等。
在 C
中使用多维数组有两种可能的方法。
压平数组
在 C
中,数组被实现为一个连续的内存块。这个信息可以用来操作存储在数组中的值,并允许快速访问特定的数组位置。
例如,
int arr[10][10];
int *ptr = (int *)arr ;
ptr[11] = 10;
利用数组的连续性特征技术被称为数组扁平化
。
不规则数组
现在考虑以下示例。
char **list;
list[0] = "United States of America";
list[1] = "India";
list[2] = "United Kingdom";
for(int i=0; i< 3 ;i++)
printf(" %d ",strlen(list[i]));
// prints 24 5 14
这种实现方式称为“不规则数组”,在使用变量大小的字符串时非常有用。流行的方法是在每个维度上进行动态内存分配。
注意:命令行参数(`char * argv []`)只作为不规则数组传递。
比较展平和不规则数组:
现在,让我们考虑以下代码片段,它比较了“展平”和“不规则”数组。
int flattened[30][20][10];
int ***ragged;
int i,j,numElements=0,numPointers=1;
ragged = (int ***) malloc(sizeof(int **) * 30);
numPointers += 30;
for( i=0; i<30; i++) {
ragged[i] = (int **)malloc(sizeof(int*) * 20);
numPointers += 20;
for(j=0; j<20; j++) {
ragged[i][j]=(int*)malloc(sizeof(int) * 10);
numElements += 10;
}
}
printf("Number of elements = %d",numElements);
printf("Number of pointers = %d",numPointers);
从上面的例子可以看出,
ragged
数组需要
631个指针
,换句话说,额外需要
631 * sizeof(int *)
的内存位置来指向
6000
个整数。而
flattened
数组只需要一个基本指针:也就是数组名称足以指向连续的
6000
个内存位置。
但是相反,
ragged
数组非常灵活。如果不知道需要多少内存位置,那么就不能有为最坏情况分配内存的奢侈。同样,在某些情况下,只有在运行时才知道所需的确切内存空间数量。在这种情况下,
ragged
数组非常方便。
数组的行主序和列主序
C
采用
行主序
顺序处理多维数组。将数组
展平
可以看作是
C
中该方面影响的一种效果。C中
行主序
顺序的重要性在于它符合大多数编程访问数据的自然方式。例如,让我们看一个遍历
N * M
2D矩阵的示例。
for(i=0; i<N; i++) {
for(j=0; j<M; j++)
printf(“%d ”, matrix[i][j]);
printf("\n");
}
矩阵中的每一行都通过快速变换列来逐个访问,C
数组按这种自然方式在内存中排列。相反,考虑以下示例,
for(i=0; i<M; i++) {
for(j=0; j<N; j++)
printf(“%d ”, matrix[j][i]);
printf("\n");
}
这会更改列索引比行索引更频繁。因此,这两个代码片段之间的效率差异很大。是的,第一个比第二个更有效!
因为第一个按C的自然顺序(行优先
)访问数组,所以它更快,而第二个需要更长时间才能跳转。随着维度数量和元素大小的增加,性能差异会加大。
因此,在使用C
中的多维数组时,考虑上述细节是很好的选择!