是否可以保证以大小为N * M的一维数组访问2D数组(T [N] [M])?

时间:2019-03-26 13:16:38

标签: c++ c++11 multidimensional-array language-lawyer

我可以确定以下代码可以工作吗?

int sum_array(int *array, size_t size)
{
  int i;
  int sum = 0;
  for (i=0;i<size;i++)
    sum += *(array+i);
  return sum;
}

int main()
{
  int two_d_array[4][3] = {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}};
  int sum = sum_array(&two_d_array[0][0], 12);
  printf("%d", sum);
}

虽然将4 x 3数组完全像12个元素的数组那样布置在内存中是合理的,但是保证是吗?由于我似乎在欺骗类型系统,因此我不确定是否会出错(例如,将填充添加到int [3])。

如果您可以详细说明如果我在数组中使用除int以外的内容会发生什么,并提供标准中的相关报价,则奖励积分。

1 个答案:

答案 0 :(得分:7)

  

例如,将填充添加到int [3]

没有任何危险。保证数组没有填充。根据注释中提到的引号,expr.add/4这样就保证了内存布局本身,而指针算法在技术上未定义:

  

通过指针(T *)遍历2D数组(T [N] [M])是否可以保证正常工作?

不幸的是,从技术上讲,并不是根据我对标准的理解。


这是标准site_user的一个版本,该版本迭代任何维度计数的多维数组的最内层元素,就好像它是平面数组一样:

std::accumulate

我还没有进行基准测试,看是否有任何开销。使用您的示例中的编译时常数输入,总和是在编译时计算的。

另一个实现;仅适用于普通类型:

template<class T, unsigned size, class BinOp = std::plus<>>
auto arr_accumulate(
    T (&arr)[size], std::remove_all_extents_t<T> init = {}, BinOp op = {})
{
    if constexpr (std::is_array_v<T>) {
        return std::accumulate(std::begin(arr), std::end(arr), init,
            [&](const auto& l, const auto& r) {
                return arr_accumulate(r, l, op);
            }
        );
    } else {
        return std::accumulate(std::begin(arr), std::end(arr), init, op);
    }
}

// usage
int sum = arr_accumulate(two_d_array, 0);