我如何声明一个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兼容的多维数组……

其他回答

下面的例子可能会有所帮助,

int main(void)
{
    double **a2d = new double*[5]; 
    /* initializing Number of rows, in this case 5 rows) */
    for (int i = 0; i < 5; i++)
    {
        a2d[i] = new double[3]; /* initializing Number of columns, in this case 3 columns */
    }

    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            a2d[i][j] = 1; /* Assigning value 1 to all elements */
        }
    }

    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout << a2d[i][j] << endl;  /* Printing all elements to verify all elements have been correctly assigned or not */
        }
    }

    for (int i = 0; i < 5; i++)
        delete[] a2d[i];

    delete[] a2d;


    return 0;
}

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

为什么答案又大又慢

建议的解决方案是创建一个指针的动态数组,然后将每个指针初始化到它自己的独立动态数组。这种方法的优点是它提供了你习惯的索引语法,所以如果你想找到矩阵在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会感谢你的。

如果行长是编译时常数,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,将产生以下结果:

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

这个答案的目的不是添加其他答案没有涵盖的新内容,而是扩展@Kevin Loney的答案。

你可以使用轻量级声明:

int *ary = new int[SizeX*SizeY]

访问语法将是:

ary[i*SizeY+j]     // ary[i][j]

但这对大多数人来说都很麻烦,可能会导致混乱。所以,你可以这样定义宏:

#define ary(i, j)   ary[(i)*SizeY + (j)]

现在可以使用非常相似的语法ary(i, j) //表示ary[i][j]。 这具有简单美观的优点,同时,使用表达式代替索引也更简单,不那么令人困惑。

要访问,比如说,ary[2+5][3+8],你可以写ary(2+ 5,3 +8),而不是看起来复杂的ary[(2+5)*SizeY +(3+8)],也就是说,它节省了括号,有助于可读性。

警告:

尽管语法非常相似,但并不相同。 如果将数组传递给其他函数,则必须以相同的名称传递SizeY(或者声明为全局变量)。

或者,如果你需要在多个函数中使用数组,那么你可以在宏定义中添加SizeY作为另一个参数,如下所示:

#define ary(i, j, SizeY)  ary[(i)*(SizeY)+(j)]

你懂的。当然,这会变得太长而没有用处,但它仍然可以防止+和*的混淆。

当然不推荐这样做,大多数有经验的用户会谴责这是一种糟糕的做法,但我还是忍不住要分享它,因为它很优雅。

编辑: 如果你想要一个适用于任意数量数组的可移植解决方案,你可以使用以下语法:

#define access(ar, i, j, SizeY) ar[(i)*(SizeY)+(j)]

然后你可以使用访问语法将任意大小的数组传递给调用:

access(ary, i, j, SizeY)      // ary[i][j]

附注:我已经测试了这些,在g++14和g++11编译器上可以使用相同的语法(作为左值和右值)。

Typedef是你的朋友

在回顾并查看了许多其他答案之后,我发现需要进行更深层次的解释,因为许多其他答案要么存在性能问题,要么迫使您使用不寻常的或繁重的语法来声明数组,或访问数组元素(或以上所有问题)。

首先,这个答案假设您在编译时知道数组的尺寸。如果你这样做,那么这是最好的解决方案,因为它将提供最好的性能,并允许您使用标准数组语法来访问数组元素。

The reason this gives the best performance is because it allocates all of the arrays as a contiguous block of memory meaning that you are likely to have less page misses and better spacial locality. Allocating in a loop may cause the individual arrays to end up scattered on multiple non-contiguous pages through the virtual memory space as the allocation loop could be interrupted ( possibly multiple times ) by other threads or processes, or simply due to the discretion of the allocator filling in small, empty memory blocks it happens to have available.

其他好处是声明语法简单,数组访问语法标准。

在c++中使用new:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {

typedef double (array5k_t)[5000];

array5k_t *array5k = new array5k_t[5000];

array5k[4999][4999] = 10;
printf("array5k[4999][4999] == %f\n", array5k[4999][4999]);

return 0;
}

或使用calloc的C样式:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {

typedef double (*array5k_t)[5000];

array5k_t array5k = calloc(5000, sizeof(double)*5000);

array5k[4999][4999] = 10;
printf("array5k[4999][4999] == %f\n", array5k[4999][4999]);

return 0;
}