我如何声明一个2d数组使用新?

比如,对于一个“普通”数组,我将:

int* ary = new int[Size]

but

int** ary = new int[sizeY][sizeX]

A)不工作/编译b)没有完成什么:

int ary[sizeY][sizeX] 

所做的事。


当前回答

如何分配一个连续的多维数组在GNU c++ ?有一个GNU扩展允许“标准”语法工作。

问题似乎来自操作符new[]。请确保使用operator new:

double (* in)[n][n] = new (double[m][n][n]);  // GNU extension

这就是全部:你得到了一个c兼容的多维数组……

其他回答

如果你的项目是CLI(公共语言运行时支持),那么:

你可以使用数组类,而不是你写的那个:

#include <array>
using namespace std;

换句话说,不是使用std名称空间和包含数组头时获得的非托管数组类,不是std名称空间和数组头中定义的非托管数组类,而是CLI的托管类数组。

使用这个类,您可以创建任意级别的数组。

下面的代码创建了一个2行3列的二维数组,类型为int,并命名为“arr”:

array<int, 2>^ arr = gcnew array<int, 2>(2, 3);

现在您可以访问数组中的元素,通过命名它并只写一个平方括号[],并在其中添加行和列,并用逗号分隔它们。

下面的代码访问我已经在上面的代码中创建的数组的第2行和第1列中的一个元素:

arr[0, 1]

只写这一行是为了读取该单元格中的值,即获取该单元格中的值,但如果添加等号,则要写入该单元格中的值,即设置该单元格中的值。 当然,你也可以使用+=,-=,*=和/=运算符,仅用于数字(int, float, double, __int16, __int32, __int64等),但你肯定已经知道了。

如果您的项目不是CLI,那么您可以使用std名称空间的非托管数组类,当然,如果您使用#include <array>,但是问题是这个数组类与CLI数组不同。创建这种类型的数组与CLI相同,除了必须删除^符号和gcnew关键字。但不幸的是,<>括号中的第二个int参数指定了数组的长度(即大小),而不是它的秩!

没有办法在这类数组中指定rank, rank是CLI数组的特性。

STD数组的行为类似于c++中的普通数组,使用指针定义,例如int*,然后:new int[size],或者不使用指针:int arr[size],但与c++中的普通数组不同,STD数组提供了可以与数组元素一起使用的函数,如fill, begin, end, size等,但普通数组什么也没有提供。

但是std数组仍然是一维数组,就像普通的c++数组一样。 但是多亏了其他人提出的关于如何将普通的c++一维数组转换为二维数组的解决方案,我们可以将同样的想法应用到std数组中,例如,根据Mehrdad Afshari的想法,我们可以编写以下代码:

array<array<int, 3>, 2> array2d = array<array<int, 3>, 2>();

这一行代码创建了一个“罐子数组”,这是一个一维数组,它的每个单元格都是或指向另一个一维数组。

如果一维数组中所有一维数组的长度/大小都相等,那么你可以将array2d变量视为一个真正的二维数组,另外你可以使用特殊的方法来处理行或列,这取决于你如何看待它,在二维数组中,std数组支持。

你也可以使用Kevin Loney的解决方案:

int *ary = new int[sizeX*sizeY];

// ary[i][j] is then rewritten as
ary[i*sizeY+j]

但如果你使用STD数组,代码必须看起来不同:

array<int, sizeX*sizeY> ary = array<int, sizeX*sizeY>();
ary.at(i*sizeY+j);

并且仍然具有std数组的独特功能。

请注意,您仍然可以使用[]括号访问std数组的元素,并且不必调用at函数。 您还可以定义并赋值一个新的int变量,该变量将计算并保持std数组中元素的总数,并使用它的值,而不是重复sizeX* sizeey

You can define your own two dimensional array generic class, and define the constructor of the two dimensional array class to receive two integers to specify the number of rows and columns in the new two dimensional array, and define get function that receive two parameters of integer that access an element in the two dimensional array and returns its value, and set function that receives three parameters, that the two first are integers that specify the row and column in the two dimensional array, and the third parameter is the new value of the element. Its type depends on the type you chose in the generic class.

你将能够通过使用普通的c++数组(指针或不指针)或std数组来实现所有这些,并使用其他人建议的想法之一,并使其易于使用,如cli数组,或像你可以在c#中定义、赋值和使用的二维数组。

如果行长是编译时常数,c++ 11允许

auto arr2d = new int [nrows][CONSTANT];

请看这个答案。像gcc这样的编译器允许将变长数组作为c++的扩展,可以使用如下所示的new来获得完全的运行时可变数组维度功能,就像C99所允许的那样,但是可移植的ISO c++仅限于第一个维度是变量。

另一个有效的选择是手动对一个大的1d数组进行2d索引,正如另一个答案所示,允许与真正的2d数组相同的编译器优化(例如,证明或检查数组不会彼此别名/重叠)。


否则,您可以使用指向数组的指针数组来支持类似连续2D数组的2D语法,尽管这不是一个有效的单一大分配。你可以使用循环初始化它,就像这样:

int** a = new int*[rowCount];
for(int i = 0; i < rowCount; ++i)
    a[i] = new int[colCount];

上面,对于colCount= 5和rowCount = 4,将产生以下结果:

在删除指针数组之前,不要忘记使用循环单独删除每一行。另一个答案中的例子。

如果只在本地或类中使用数组,则可以使用lambda表达式创建类数组对象。

int main(int argc, char **argv) {
  srand(time(0));
  int w = rand() % 20 + 10;
  int h = rand() % 20 + 10;
  {
    // Here. Only one line and no memory leak.
    auto arr = [=, p = std::make_unique<int[]>(w * h)](int i, int j) -> int & { return *&p[i * w + j]; };
    arr(1, 0) = 6;
    std::cout << arr(1, 0) << '\n';
  }
}

该对象与int[][]不兼容,要将其作为参数传递,需要模板。但是当你访问一个元素时,它可以让你摆脱正确获取[i * w + j]的麻烦。

你也可以使用一个裸std::unique_ptr<int[]>和一个在lambda中实现的getter。但你可能会犯错误,引用不明确。

如何分配一个连续的多维数组在GNU c++ ?有一个GNU扩展允许“标准”语法工作。

问题似乎来自操作符new[]。请确保使用operator new:

double (* in)[n][n] = new (double[m][n][n]);  // GNU extension

这就是全部:你得到了一个c兼容的多维数组……

尽管这个流行的答案将为您提供所需的索引语法,但它的效率是双重的:在空间和时间上都大而慢。有更好的办法。

为什么答案又大又慢

建议的解决方案是创建一个指针的动态数组,然后将每个指针初始化到它自己的独立动态数组。这种方法的优点是它提供了你习惯的索引语法,所以如果你想找到矩阵在x,y位置的值,你说:

int val = matrix[ x ][ y ];

这是因为矩阵[x]返回一个指向数组的指针,然后用[y]作为索引。分解一下:

int* row = matrix[ x ];
int  val = row[ y ];

方便,是吗?我们喜欢[x][y]语法。

但是这个解决方案有一个很大的缺点,那就是它既胖又慢。

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 also take 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.

它慢还有另一个原因。这些单独的分配往往位于内存的不连续部分。一行的地址可能是1000,另一行的地址可能是100000——你可以理解。这意味着当你在穿越矩阵时,你就像一个狂野的人一样在记忆中跳跃。这往往会导致缓存丢失,从而大大降低处理时间。

所以,如果你绝对必须有你可爱的[x][y]索引语法,使用这个解决方案。如果你想要快速和小巧(如果你不关心这些,为什么要用c++ ?),你需要一个不同的解决方案。

不同的解决方案

更好的解决方案是将整个矩阵分配为单个动态数组,然后使用自己的(稍微)聪明的索引数学来访问单元格。索引的数学运算非常巧妙;不,这一点也不聪明:这是显而易见的。

class Matrix
{
    ...
    size_t index( int x, int y ) const { return x + m_width * y; }
};

给定这个index()函数(我想象它是一个类的成员,因为它需要知道矩阵的m_width),您可以访问矩阵数组中的单元格。矩阵数组是这样分配的:

array = new int[ width * height ];

所以在缓慢的,高脂肪的溶液中

array[ x ][ y ]

...这是一个快速,小的解决方案:

array[ index( x, y )]

很难过,我知道。但你会习惯的。你的CPU会感谢你的。