C++堆上的多维数组

24

我该如何动态分配多维数组?

11个回答

24

如果您已经知道嵌套维度的大小,您也可以使用 new 直接分配多维数组:

typedef int dimensions[3][4];

dimensions * dim = new dimensions[10];
dim[/* from 0 to 9 */][/* from 0 to 2 */][/* from 0 to 3 */] = 42;
delete [] dim;

可以传递由运行时确定的值,而不是10。由于它不是类型操作符new返回的一部分,因此被允许。如果你知道列数,但想保持行数可变,这将非常方便。typedef使代码更易读。


3
这个答案有些刻薄:https://dev59.com/mnVC5IYBdhLWcg3wvT1a ,但希望能解决您的疑虑 :) - Johannes Schaub - litb
不错,litb。我不知道你能做到那个。 - e.James

6
看这个: 由Marshall Cline编写的C++ FAQ 请查看“如何使用new分配多维数组?”和“但是以前的FAQ中的代码非常棘手且容易出错!有没有更简单的方法?”部分。

我有一段时间没有考虑过C++ FAQ了。它曾经是我最喜欢的编程读物之一,与Strostrup的书籍并列。 - Rich
FAQ [16.16]似乎不正确。它使用new[]为行分配内存。然后将每个指针设置为NULL并重新分配它。它从未释放设置为NULL的内存,因此泄漏了该内存。请检查。 - user236215

6

为了完整起见,以下是在你预先知道数组范围时以更好的方式在C++中执行它的方法。使用以下类的好处是,您不必担心在数据上调用delete[]。这意味着这个类将是异常安全的,并且所有关于RAII的其他优点也将得到体现。

template<typename T, int width, int height>
class MultiArray
{
    private:
        typedef T cols[height];
        cols * data;
    public:
        T& operator() (int x, int y) { return data[x][y]; }
        MultiArray() { data = new cols[width]; }
        ~MultiArray() { delete [] data; }
};

使用方法:

MultiArray<int, 10, 10> myArray;
myArray(2, 3) = 4;
cout << myArray(2, 3);
编辑:顺便说一下,如果你在运行时不知道数组边界,这里是你可以使用的设置:
template<typename T>
class Array2D
{
    private:
        const int width;
        T * data;
    public:
        T& operator() (int x, int y) { return data[y*width + x]; }
        Array2D(const int w, const int h) : width(w) { data = new T[w*h]; }
        ~Array2D() { delete [] data; }
};

使用方法:

Array2D myArray(10, 10);
myArray(3, 4) = 42;
cout << myArray(3, 4);

6
如何使用Boost.Multiarray?我相信它可以很好地满足您的需求!http://www.boost.org/doc/libs/1_37_0/libs/multi_array/doc/user.html#sec_introduction 以下是文档页面的摘录:
 #include < boost/multi_array.hpp >

 #include < cassert >

int main () 

{

  // Create a 3D array that is 3 x 4 x 2

  typedef boost::multi_array< double, 3 > array_type;

  typedef array_type::index index;

  array_type A(boost::extents[3][4][2]);


  // Assign values to the elements

  int values = 0;

  for(index i = 0; i != 3; ++i) 

    for(index j = 0; j != 4; ++j)

      for(index k = 0; k != 2; ++k)

        A[i][j][k] = values++;

  // Verify values

  int verify = 0;

  for(index i = 0; i != 3; ++i) 

    for(index j = 0; j != 4; ++j)

      for(index k = 0; k != 2; ++k)

        assert(A[i][j][k] == verify++);

  return 0;

}

4

std::vector<std::vector<int> >应该被提及,因为它通常是最简单的方法。但是,请注意它是非矩形的。并不是每个std::vector<int>都需要具有相同的长度。


对于一维数组来说很简单,但是两个维度会使事情变得复杂。您必须明确地将每个元素初始化为您想要的大小。 - Mark Ransom
1
没错,但这并不困难:std::vector<std::vector<int> > myarray(height, std::vector<int>(width)); 创建了一个由0填充的矩形,索引为[row][column]。行在内存中是连续的,而列则不是。 - Steve Jessop
@MarkRansom,实际上,对我来说这就是这种方法的好处。当维度长度一致时,boost::multi_array是一个很棒的容器,而vector<vector<...>>则适用于动态非常量长度数组...尽管这几乎从不需要...但当需要时,这就是正确的选择! - Elliott

4

我很惊讶没有人提到boost::multi_array。就在上周,我需要在程序中使用一个二维数组,并发现这比我之前自己编写的解决方案(其他评论中都提到了)更容易且编码速度更快。


3
这是我得到的实现方式:我声明了一个连续的int块,而不是在我的for循环内创建新块,这样就不会在所有地方都引起页面错误。感谢eJames指出这段代码最初的问题。
int width = 10, height = 10, totalSize = width*height;
int **myArray = new int*[width];
int *data = new int[totalSize];

for ( int i = 0; i < height; ++i )
{
    myArray[i] = data + (i*width);
}

// do some things here

delete[] data;
delete[] myArray;

这段代码无法按照所示工作。具体来说,您循环中对myArray[i]的写入将会到处乱跑。请查看我修改后的循环:https://dev59.com/sHRC5IYBdhLWcg3wUfJ2 - e.James

2
作为另一种选择,STLSoft 包括一个 fixed_array_2d 类(还有 3D 和 4D 版本)。与此处提供的自制解决方案相比,它具有类似的实现但更完整的功能集(完全支持迭代器等)。与 boost::multi_array 相比,它更轻量级,对不太兼容的 C++ 编译器更加友好,但(故意)缺少一些 multi_array 的功能。

2

您的循环不能正确地将指针值写入myArray。我建议改为以下方式:

int width = 10;
int height = 10;
int ** myArray = new int*[width];
int * data = new int[width*height];
int * index = data;
for (int i = 0; i < width; i++)
{
    myArray[i] = index;
    index += height;
}

// ...

delete[] data;
delete[] myArray;

你说得对;我曾经让它工作了,然后重构了它,但没有检查它是否能正常工作。也许我应该停止破坏构建... - eplawless

0

如果你正确地跨越了一定数量的元素,你可以将一维数组索引为二维、三维或 N 维数组。例如,如果我有 10 行和 10 列,我知道如果我在第 3 行,我至少要跨越 30 个元素才能到达它。

对于简单的二维数组,我更喜欢这种表示法,因为我不需要担心嵌套级别的指针。缺点是索引符号比较混乱。以下是一个具有 n 行和 m 列的二维数组的示例:

int *matrix = new int[n*m];

//set element (3,7) to 10
matrix[3*m+7] = 10;

//print the matrix
for (int i = 0; i < n; i++) {
  for (int j = 0; j < m; j++) {
    cout << matrix[i*m+j] << ' ';
  }
  cout << '\n';
}

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