[英]2-Dimensional array in memory in ANSI C
我在这里和其他网站上看过很多人说如果宣布这样的话:
double a[5][2];
它将在内存中分配,如:连续块,如:
a[0][0] | a[0][1] | a[1][0] | a[1][1] | ....etc
但这总是一个规律吗? 我想创建一个函数来乘以可变大小的矩阵,但在纯CI中,如果不知道至少一个维度,就不能通过参数传递矩阵。 所以我做了这个:
void MatMult(double* m1, double* m2, double* res, int h, int w, int l)
{
int i, j, k;
for (i = 0; i < h; i++)
{
for (j = 0; j < w; j++)
{
double p_res = 0;
for (k = 0; k < l; k++)
{
p_res += (*(m1+i*l+k))*(*(m2+k*w+j));
}
*(res+i*w+j)=p_res;
}
}
}
随叫随到:
double m1[2][3], m2[3][1], m3[2][1];
...
MatMult(&(m1[0][0]),&(m2[0][0]),&(m3[0][0]),2,1,3);
它奏效了。 但这会一直有效还是我应该注意的例外情况,如内存对齐或类似的东西?
要将2D数组传递给函数,您必须更改接口
void MatMult(size_t h, size_t w, size_t l. double m1[h][w], double m2[w][l], double res[h][l]);
或类似的:
此外,我在这里使用了size_t
,因为这是所有索引计算的正确类型。
这适用于所有实现C99的编译器。 (基本上所有人都可以做到。)
是的,它总能奏效。 声明像你做的ara保证是“连续的”,这意味着他们的物品将被紧紧包装起来。 所以,如果你声明double[55]
你就会知道[50]
-th元素总是会在[49]
元素之后,没有可感知的间隙。
我想,但我不完全确定,对于一些非常罕见的数据类型(如包括不平衡的位域等),“对齐”仍然可以启动并抵消某些东西。
我不确定。
但
即使
(参见Jens评论)如果编译器添加了一些对齐偏移,它将在单个数据元素内部或在元素之间的boudary中这样做,并且在两种情况下编译器都会知道它。 因此,它应该在每个[], ->, .
应用所有必需的更正[], ->, .
操作,只要它仍然具有所有必需的类型信息(double-number)。 如果删除类型信息并开始通过“无类型”(或错误类型)指针访问数组,例如:
double array[50];
char* p = (char*)array;
int size = sizeof(double);
for(i=0;i<50;++i)
.. *(double*)(p+size) ..
那么编译器当然没有类型信息,也无法应用正确的对齐偏移。 但是如果你按照上面所做的那样做,你可能已经知道了风险。
接下来的是,没有二维数组这样的东西。 既不是C语言,也不是C ++语言。
定义为double[5][2]
的数组是double的数组(2)的数组(5)。 CMIIW,我可以交换它们。 无论如何,关键是'double'是一种数据类型,是更高级别1D阵列的元素。 然后, double[2]
是数据类型和更高级别1D数组的元素,依此类推。
现在,请记住数组的“顺序+连续”布局:
double -> DD
double[2] -> [DD | DD]
double[5][2] -> [ {DD:DD} | {DD:DD} | {DD:DD} | {DD:DD} | {DD:DD} ]
由于数组必须是连续的和连续的,所以double [2]必须将其元素布局如上 - 显而易见。
但是,由于double [5] [2]是一个数组,它的数组是[5],并且由于它的元素是double [2] - 它必须以相同的方式布局它的元素。 首先是整个元素,然后是第二个整数元素,依此类推。
就像double [2]不能将其双精度“拆分”成分散的1字节块一样,double [5] [2]不能拆分它的数组[2]。
通过使用double a[5][2]
,您将在堆栈中创建二维数组,它始终是一个连续的内存块。 另一方面,如果您尝试在堆上创建二维数组(即使用malloc),则无法保证您将获得连续的内存块,因此您可能无法以线性方式遍历已分配的内存。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.