我将如何动态分配多维数组?
11 回答
如果你已经知道嵌套维度的大小,你也可以使用 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 使代码更容易阅读。
请参阅: Marshall Cline 的 C++ 常见问题解答
请参阅“如何使用 new 分配多维数组?” 和“但是之前的常见问题解答的代码非常棘手且容易出错!难道没有更简单的方法吗?” 部分。
为了完整起见,当您提前知道数组边界时,这是在 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);
使用 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;
}
std::vector<std::vector<int> >
应该提到,因为它通常是最简单的方法。但是,请注意它是非矩形的。并非每个人都std::vector<int>
需要具有相同的长度。
我很惊讶还没有人提到boost::multi_array
。就在上周,我在一个程序中需要一个 2D 数组,发现它比我之前提出的自制解决方案更容易,编码也更快(所有这些都在其他评论中提到) .
这是我的实现;我声明了一个连续的int
s 块,而不是在我的 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
正确写入指针值。我建议改为:
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;
作为另一种选择,STLSoft包括一个fixed_array_2d类(以及 3D 和 4D 版本)。与这里给出的自制解决方案相比,它具有类似的实现,但功能集更完整(完全支持迭代器等)。与 boost::multi_array 相比,它在不完全兼容的 C++ 编译器上更轻、更容易,但(故意)缺少 multi_array 的一些特性。
如果您只是在正确数量的元素上留出空间,则可以将一维索引为 2、3 或 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';
}
这是另一个帖子上的帖子的复制。它完全符合您的要求,无需提前知道数组尺寸,也无需使用 boost 或 STL。
这是一个例程,它在连续的内存空间中分配维度为 N1 x N2 x N3 的 3D 数组,同时允许您使用 a[i][j][k] 语法进行运算符访问。该数组是动态但连续的,因此它比 vector<> 方法和 new[] 调用循环具有巨大优势。
template <class T> T ***Create3D(int N1, int N2, int N3)
{
T *** array = new T ** [N1];
array[0] = new T * [N1*N2];
array[0][0] = new T [N1*N2*N3];
int i,j,k;
for( i = 0; i < N1; i++) {
if (i < N1 -1 ) {
array[0][(i+1)*N2] = &(array[0][0][(i+1)*N3*N2]);
array[i+1] = &(array[0][(i+1)*N2]);
}
for( j = 0; j < N2; j++) {
if (j > 0) array[i][j] = array[i][j-1] + N3;
}
}
cout << endl;
return array;
};
template <class T> void Delete3D(T ***array) {
delete[] array[0][0];
delete[] array[0];
delete[] array;
};
稍后在您的实施例程中...
int *** array3d;
int N1=4, N2=3, N3=2;
int elementNumber = 0;
array3d = Create3D<int>(N1,N2,N3);
//equivalently, a 'flat' array could be obtained with
//int * array = array3d[0][0];
cout << "{" << endl;
for (i=0; i<N1; i++) {
cout << "{";
for (j=0; j<N2; j++) {
cout << "{";
for (k=0; k<N3; k++) {
array3d[i][j][k] = elementNumber++;
cout << setw(4) << array3d[i][j][k] << " ";
//or if you're using the flat array:
//array[i*N2*N3 + j*N3 + k] = elementNumber++;
}
cout << "}";
}
cout << "}";
cout << endl ;
}
cout << "}" << endl;
Delete3D(array3d);
给出输出:
{
{{ 0 1 }{ 2 3 }{ 4 5 }}
{{ 6 7 }{ 8 9 }{ 10 11 }}
{{ 12 13 }{ 14 15 }{ 16 17 }}
{{ 18 19 }{ 20 21 }{ 22 23 }}
}