如何在不复制数据的情况下转换平面数组和多维数组?

3
我有一些数据以多维数组的形式结构化,例如double[][],我需要将其传递给一个函数,该函数期望一个单一的线性数组double[]和多维表示法的维度元数据。
例如,我可能有一个3×5的多维数组,我需要将其作为15个元素的平坦数组传递,同时传递高度和宽度参数,以便函数知道它是一个3x5的数组而不是一个5x3的数组。
然后,该函数将返回一个平坦数组和大小元数据,我需要使用这些数据将数据转换回多维类型。
我相信在内存中,平坦和多维表示法的数据布局完全相同。唯一的区别在于执行索引操作的方式不同。因此,我想通过类型转换而不是复制数组值来进行“转换”。
对于相同总大小的多维数组和平坦数组之间的类型转换,最正确且易读的方式是什么?
我实际上知道编译时多维数组的维度。数组大小不是动态的。

我认为你可以将多维数组视为一个平面数组来处理,这样应该就没问题了。(例如,如果你有一个 double a[5][5] 数组,那么 a[8] 应该返回 a[1][3] 的值)。 - wohe1
4个回答

2
最正确的方法已经由@Maxim Egorushkin和@ypnos给出:double *flat = &multi[0][0];。使用任何好的编译器都可以正常工作。但不幸的是,这不是有效的C++代码,并会引发未定义行为。
问题在于对于一个数组double multi[N][M];(其中NM是编译时常量表达式),&multi[0][0]是一个大小为M的数组的第一个元素的地址。因此,只能进行指针算术运算到M。有关更多详细信息,请参见我提出的另一个问题

多维数组不是保证在连续的内存块中吗? - Piotr Siupa
是的,它们确实是。但根据标准的措辞,这还不足以使其成为数组。简而言之,数组需要是一系列连续的元素块,但仅仅是连续的块并不能构成一个声明的数组。 - Serge Ballesta
很有趣。不过,我想不出这里可能出错的地方。我相信他们不会没有充分理由就写入标准,但也许这只是一个疏忽。或者他们明确说明不允许这种数组转换? - Piotr Siupa
1
据我所知,没有任何明确说明它是不正确的。仅仅因为没有定义,使用它会导致未定义的行为...当然,在旧版的C代码中这种用法很常见,而且为了不破坏大型代码库,编译器仍然接受它。在新代码中是否要使用它,这就取决于你自己了... - Serge Ballesta

1
什么是将多维数组和平面数组在总大小相同的情况下进行强制类型转换的最正确和可读的方法?
第一个数组元素的地址与数组的地址重合。您可以传递第一个元素的地址,不需要进行强制类型转换。

我需要将其转换回具体的多维数组类型,而不是指针,以便与提供和期望这些类型的外部代码进行交互。 - Hydrargyrum

0

您可以将类型转换为数组的引用。这需要使用一些花哨的C++类型语法,但作为回报,它允许使用所有适用于数组的功能,例如for each循环。

#include <iostream>

using namespace std;

int main()
{
    static constexpr size_t x = 5, y = 3;
    unsigned multiArray[x][y];
    for (size_t i = 0; i != x; ++i)
        for (size_t j = 0; j != y; ++j)
            multiArray[i][j] = i * j;

    static constexpr size_t z = x * y;
    unsigned (&singleArray)[z] = (unsigned (&)[z])multiArray[0][0];
    for (const unsigned value : singleArray)
        cout << value << ' ';
    cout << endl;

    return 0;
}

请注意,这种基于转换的方法只适用于真正的多维数组。如果它是一个数组的数组(例如unsigned **multiArray;),它不会在连续的内存块中分配,并且转换无法绕过这一点。

0

我认为最流行的方法是:

double *flat = &multi[0][0];

这是在C语言中完成的,您可以使用简单的C数组进行操作。

如果您的维度在编译时已知,您还可以查看std::array,但它不是多维的,因此如果您级联它,您将失去连续的布局。


double A[5][5]; (&A[0][0])[10] 由于溢出了仅有5个元素的 A[0] 导致 UB。 - tstanisl
是的,这在被接受的答案中有解释。 - ypnos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接