如何使用 new 在 C++ 中声明一个二维数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/936687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I declare a 2d array in C++ using new?
提问by user20844
How do i declare a 2d array using new?
如何使用 new 声明一个二维数组?
Like, for a "normal" array I would:
就像,对于“正常”数组,我会:
int* ary = new int[Size]
but
但
int** ary = new int[sizeY][sizeX]
a) doesn't work/compile and b) doesn't accomplish what:
a) 不工作/编译和 b) 不完成什么:
int ary[sizeY][sizeX]
does.
做。
回答by Mehrdad Afshari
A dynamic 2D array is basically an array of pointers to arrays. You can initialize it using a loop, like this:
动态二维数组基本上是指向数组的指针数组。您可以使用循环对其进行初始化,如下所示:
int** a = new int*[rowCount];
for(int i = 0; i < rowCount; ++i)
a[i] = new int[colCount];
The above, for colCount= 5
and rowCount = 4
, would produce the following:
以上,对于colCount= 5
和rowCount = 4
,将产生以下结果:
回答by Kevin Loney
int** ary = new int[sizeY][sizeX]
should be:
应该:
int **ary = new int*[sizeY];
for(int i = 0; i < sizeY; ++i) {
ary[i] = new int[sizeX];
}
and then clean up would be:
然后清理将是:
for(int i = 0; i < sizeY; ++i) {
delete [] ary[i];
}
delete [] ary;
EDIT:as Dietrich Epp pointed out in the comments this is not exactly a light weight solution. An alternative approach would be to use one large block of memory:
编辑:正如 Dietrich Epp 在评论中指出的那样,这并不是一个轻量级的解决方案。另一种方法是使用一大块内存:
int *ary = new int[sizeX*sizeY];
// ary[i][j] is then rewritten as
ary[i*sizeY+j]
回答by OldPeculier
Although this popular answerwill give you your desired indexing syntax, it is doubly inefficient: big and slow both in space and time. There's a better way.
虽然这个流行的答案会给你你想要的索引语法,但它的效率是双重的:空间和时间都大而慢。有更好的方法。
Why That Answer is Big and Slow
为什么这个答案又大又慢
The proposed solution is to create a dynamic array of pointers, then initializing each pointer to its own, independent dynamic array. The advantageof this approach is that it gives you the indexing syntax you're used to, so if you want to find the value of the matrix at position x,y, you say:
建议的解决方案是创建一个动态指针数组,然后将每个指针初始化为它自己的独立动态数组。这种方法的优点是它为您提供了您习惯的索引语法,因此如果您想在位置 x,y 处找到矩阵的值,您可以说:
int val = matrix[ x ][ y ];
This works because matrix[x] returns a pointer to an array, which is then indexed with [y]. Breaking it down:
这是有效的,因为 matrix[x] 返回一个指向数组的指针,然后用 [y] 索引该数组。分解它:
int* row = matrix[ x ];
int val = row[ y ];
Convenient, yes? We like our [ x ][ y ] syntax.
方便吧?我们喜欢我们的 [ x ][ y ] 语法。
But the solution has a big disadvantage, which is that it is both fat and slow.
但是该解决方案有一个很大的缺点,就是既胖又慢。
Why?
为什么?
The reason that it's both fat and slow is actually the same. Each "row" in the matrix is a separately allocated dynamic array. Making a heap allocation is expensive both in time and space. The allocator takes time to make the allocation, sometimes running O(n) algorithms to do it. And the allocator "pads" each of your row arrays with extra bytes for bookkeeping and alignment. That extra space costs...well...extra space. The deallocator will alsotake extra time when you go to deallocate the matrix, painstakingly free-ing up each individual row allocation. Gets me in a sweat just thinking about it.
既胖又慢的原因其实是一样的。矩阵中的每一“行”都是一个单独分配的动态数组。进行堆分配在时间和空间上都是昂贵的。分配器需要时间进行分配,有时运行 O(n) 算法来完成。分配器用额外的字节“填充”每个行数组,用于簿记和对齐。额外的空间需要……嗯……额外的空间。该释放器将还需要额外的时间,当你去解除分配矩阵,精心免费-ING了每个单排分配。想想就让我汗流浃背。
There's another reason it's slow. These separate allocations tend to live in discontinuous parts of memory. One row may be at address 1,000, another at address 100,000—you get the idea. This means that when you're traversing the matrix, you're leaping through memory like a wild person. This tends to result in cache misses that vastly slow down your processing time.
速度慢还有一个原因。这些单独的分配往往存在于内存的不连续部分。一行可能位于地址 1,000,另一行位于地址 100,000 — 您明白了。这意味着当你遍历矩阵时,你就像一个野人一样在记忆中跳跃。这往往会导致缓存未命中,从而大大减慢您的处理时间。
So, if you absolute must have your cute [x][y] indexing syntax, use that solution. If you want quickness and smallness (and if you don't care about those, why are you working in C++?), you need a different solution.
因此,如果您绝对必须拥有可爱的 [x][y] 索引语法,请使用该解决方案。如果你想要快速和小巧(如果你不关心这些,你为什么用 C++ 工作?),你需要一个不同的解决方案。
A Different Solution
不同的解决方案
The better solution is to allocate your whole matrix as a single dynamic array, then use (slightly) clever indexing math of your own to access cells. The indexing math is only very slightly clever; nah, it's not clever at all: it's obvious.
更好的解决方案是将整个矩阵分配为单个动态数组,然后使用您自己的(稍微)巧妙的索引数学来访问单元格。索引数学只是非常聪明;不,它一点也不聪明:这很明显。
class Matrix
{
...
size_t index( int x, int y ) const { return x + m_width * y; }
};
Given this index()
function (which I'm imagining is a member of a class because it needs to know the m_width
of your matrix), you can access cells within your matrix array. The matrix array is allocated like this:
给定这个index()
函数(我想象它是一个类的成员,因为它需要知道m_width
矩阵的 ),你可以访问矩阵数组中的单元格。矩阵数组是这样分配的:
array = new int[ width * height ];
So the equivalent of this in the slow, fat solution:
因此,在缓慢而丰富的解决方案中,这等效于:
array[ x ][ y ]
...is this in the quick, small solution:
...这是快速、小型的解决方案:
array[ index( x, y )]
Sad, I know. But you'll get used to it. And your CPU will thank you.
难过,我知道。但是你会习惯的。你的 CPU 会感谢你。
回答by Mohammad Alaggan
In C++11 it is possible:
在 C++11 中是可能的:
auto array = new double[M][N];
This way, the memory is not initialized. To initialize it do this instead:
这样,内存不会被初始化。要初始化它,请执行以下操作:
auto array = new double[M][N]();
Sample program (compile with "g++ -std=c++11"):
示例程序(使用“g++ -std=c++11”编译):
#include <iostream>
#include <utility>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>
using namespace std;
int main()
{
const auto M = 2;
const auto N = 2;
// allocate (no initializatoin)
auto array = new double[M][N];
// pollute the memory
array[0][0] = 2;
array[1][0] = 3;
array[0][1] = 4;
array[1][1] = 5;
// re-allocate, probably will fetch the same memory block (not portable)
delete[] array;
array = new double[M][N];
// show that memory is not initialized
for(int r = 0; r < M; r++)
{
for(int c = 0; c < N; c++)
cout << array[r][c] << " ";
cout << endl;
}
cout << endl;
delete[] array;
// the proper way to zero-initialize the array
array = new double[M][N]();
// show the memory is initialized
for(int r = 0; r < M; r++)
{
for(int c = 0; c < N; c++)
cout << array[r][c] << " ";
cout << endl;
}
int info;
cout << abi::__cxa_demangle(typeid(array).name(),0,0,&info) << endl;
return 0;
}
Output:
输出:
2 4
3 5
0 0
0 0
double (*) [2]
回答by Isvara
I presume from your static array example that you want a rectangular array, and not a jagged one. You can use the following:
我从您的静态数组示例中假设您想要一个矩形数组,而不是锯齿状数组。您可以使用以下内容:
int *ary = new int[sizeX * sizeY];
Then you can access elements as:
然后你可以访问元素:
ary[y*sizeX + x]
Don't forget to use delete[] on ary
.
不要忘记使用 delete[] on ary
。
回答by Levi Morrison
There are two general techniques that I would recommend for this in C++11 and above, one for compile time dimensions and one for run time. Both answers assume you want uniform, two-dimensional arrays (not jagged ones).
在 C++11 及更高版本中,我会为此推荐两种通用技术,一种用于编译时维度,一种用于运行时。两个答案都假设您想要统一的二维数组(不是锯齿状数组)。
Compile time dimensions
编译时间维度
Use a std::array
of std::array
and then use new
to put it on the heap:
使用 a std::array
ofstd::array
然后使用new
将其放在堆上:
// the alias helps cut down on the noise:
using grid = std::array<std::array<int, sizeX>, sizeY>;
grid * ary = new grid;
Again, this only works if the sizes of the dimensions are known at compile time.
同样,这仅在编译时已知维度的大小时才有效。
Run time dimensions
运行时维度
The best way to accomplish a 2 dimensional array with sizes only known at runtime is to wrap it into a class. The class will allocate a 1d array and then overload operator []
to provide indexing for the first dimension.
This works because in C++ a 2D array is row-major:
完成大小仅在运行时已知的二维数组的最佳方法是将其包装到一个类中。该类将分配一个operator []
一维数组,然后重载以提供第一维的索引。这是有效的,因为在 C++ 中,二维数组是行优先的:
(Taken from http://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays/)
(取自http://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays/)
A contiguous sequence of memory is good for performance reasons and is also easy to clean up. Here's an example class that omits a lot of useful methods but shows the basic idea:
出于性能原因,连续的内存序列有好处,也易于清理。这是一个示例类,它省略了许多有用的方法,但显示了基本思想:
#include <memory>
class Grid {
size_t _rows;
size_t _columns;
std::unique_ptr<int[]> data;
public:
Grid(size_t rows, size_t columns)
: _rows{rows},
_columns{columns},
data{std::make_unique<int[]>(rows * columns)} {}
size_t rows() const { return _rows; }
size_t columns() const { return _columns; }
int *operator[](size_t row) { return row * _columns + data.get(); }
int &operator()(size_t row, size_t column) {
return data[row * _columns + column];
}
}
So we create an array with std::make_unique<int[]>(rows * columns)
entries. We overload operator []
which will index the row for us. It returns an int *
which points to the beginning of the row, which can then be dereferenced as normal for the column. Note that make_unique
first ships in C++14 but you can polyfill it in C++11 if necessary.
所以我们创建了一个包含std::make_unique<int[]>(rows * columns)
条目的数组。我们重载operator []
将为我们索引行。它返回int *
指向行开头的 ,然后可以像正常的列一样取消引用。请注意,它make_unique
首先在 C++14 中发布,但如果需要,您可以在 C++11 中对其进行 polyfill。
It's also common for these types of structures to overload operator()
as well:
这些类型的结构也很常见重载operator()
:
int &operator()(size_t row, size_t column) {
return data[row * _columns + column];
}
Technically I haven't used new
here, but it's trivial to move from std::unique_ptr<int[]>
to int *
and use new
/delete
.
从技术上讲,我没有new
在这里使用过,但是从std::unique_ptr<int[]>
to移动到int *
并使用new
/是微不足道的delete
。
回答by Mark Ransom
This question was bugging me - it's a common enough problem that a good solution should already exist, something better than the vector of vectors or rolling your own array indexing.
这个问题困扰着我 - 这是一个足够普遍的问题,应该已经存在一个好的解决方案,比向量的向量或滚动你自己的数组索引更好。
When something ought to exist in C++ but doesn't, the first place to look is boost.org. There I found the Boost Multidimensional Array Library, multi_array
. It even includes a multi_array_ref
class that can be used to wrap your own one-dimensional array buffer.
当某些东西应该在 C++ 中存在但不存在时,首先要查看的是boost.org。在那里我找到了Boost 多维数组库,multi_array
. 它甚至包括一个multi_array_ref
可用于包装您自己的一维数组缓冲区的类。
回答by doctorlai
Why not use STL:vector? So easy, and you don't need to delete the vector.
为什么不使用 STL:vector?如此简单,您无需删除向量。
int rows = 100;
int cols = 200;
vector< vector<int> > f(rows, vector<int>(cols));
f[rows - 1][cols - 1] = 0; // use it like arrays
You can also initialise the 'arrays', just give it a default value
您也可以初始化“数组”,只需给它一个默认值
const int DEFAULT = 1234;
vector< vector<int> > f(rows, vector<int>(cols, DEFAULT));
Source: How to Create 2, 3 (or Multi) Dimensional Arrays in C/C++?
回答by akshay_rahar
A 2D array is basically a 1D array of pointers, where every pointer is pointing to a 1D array, which will hold the actual data.
二维数组基本上是一维指针数组,其中每个指针都指向一个一维数组,该数组将保存实际数据。
Here N is row and M is column.
这里 N 是行,M 是列。
dynamic allocation
动态分配
int** ary = new int*[N];
for(int i = 0; i < N; i++)
ary[i] = new int[M];
fill
填
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++)
ary[i][j] = i;
打印
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++)
std::cout << ary[i][j] << "\n";
free
自由
for(int i = 0; i < N; i++)
delete [] ary[i];
delete [] ary;
回答by etham
How to allocate a contiguous multidimensional array in GNU C++? There's a GNU extension that allows the "standard" syntax to work.
如何在 GNU C++ 中分配一个连续的多维数组?有一个 GNU 扩展允许“标准”语法工作。
It seems the problem come from operator new []. Make sure you use operator new instead :
似乎问题来自运算符 new []。确保您使用 operator new 代替:
double (* in)[n][n] = new (double[m][n][n]); // GNU extension
And that's all : you get a C-compatible multidimensional array...
就是这样:你得到了一个 C 兼容的多维数组......