繁体   English   中英

ANSI C中内存中的二维数组

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM