如何正确填充在堆上分配的二维数组?

How can I properly fill a 2D array that is allocated on the heap?

本文关键字:分配 二维数组 何正确 填充      更新时间:2023-10-16

我在堆上创建了一个二维数组。我想用数字填充数组。我尝试了两种方法。第一次尝试有点工作,但问题是当我尝试删除它时程序会崩溃。我所做的第二次尝试可以在使用数组后将其删除,但数组未以正确的方式填充。

所以我是这样声明二维数组的:

int** matrix = new int*[rowSize];
for (int i = 0; i < rowSize; i++) {
matrix[i] = new int[ColSize];
}

然后我像这样填写它:

int matrixI0[]{1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1};
int matrixI1[]{1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1};
int matrixI2[]{1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1};
int matrixI3[]{1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1};
int matrixI4[]{1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1};
int matrixI5[]{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1};
int matrixI6[]{0, 0, 1, 0, 0, 0, 1, 1, 1, 0 ,0, 1};

matrix[0] = matrixI0;
matrix[1] = matrixI1;
matrix[2] = matrixI2;
matrix[3] = matrixI3;
matrix[4] = matrixI4;
matrix[5] = matrixI5;
matrix[6] = matrixI6;

当我以这种方式填充它时,数组的行为方式是我想要的,并且在使用该数组的后续方法中得到了预期的结果。

但是,当我尝试删除它时:

for (int i = 0; i < rowSize; ++i) {
delete[] matrix[i];
}
delete[] matrix;

我收到一个抛出的异常,其中包含以下错误消息"Test.exe 已触发断点。当然,如果我在发布中运行它,程序会崩溃。

我第二次尝试填充数组如下所示:

int matrixI0[]{1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1};
int matrixI1[]{1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1};
int matrixI2[]{1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1};
int matrixI3[]{1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1};
int matrixI4[]{1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1};
int matrixI5[]{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1};
int matrixI6[]{0, 0, 1, 0, 0, 0, 1, 1, 1, 0 ,0, 1};

matrix[0][0] = *matrixI0;
matrix[1][0] = *matrixI1;
matrix[2][0] = *matrixI2;
matrix[3][0] = *matrixI3;
matrix[4][0] = *matrixI4;
matrix[5][0] = *matrixI5;
matrix[6][0] = *matrixI6;

现在当我删除数组时没有问题,但现在数组的行为方式不是我想要的,当我测试使用该数组的方法时,我得到的结果与数组刚刚用零填充一样。

我知道我在第二次尝试中做得不对,但我只是这样做是为了看看必须做什么才能成功删除数组。

所以总结一下,我的问题是我应该如何以正确填充的方式填充二维数组,但它也会被成功删除?

谢谢!

快速回答:不要使用原始数组,这很C++,只需使用正确重载operator=std::vector<int>/std::array<int>,它们将为您完成工作,例如:

std::vector<std::vector<int>> matrix(7);
matrix[0] = { 1, 3, 3};

长答案

您不是在堆上填充数组,而是将它们在matrix中的引用替换为本地数组,这些数组在退出作用域时会被删除,并且在任何情况下都无法删除。

为了解释这个问题,让我们保持简单,假设堆上有单个数组

int* row = new int[rowSize];

所以你有一个变量行,它存储一个内存地址到堆上分配的数组:

| row | ------> |x|x|x|x|x|x|x|

现在你做了:

int myRow[] = { 1, 2, 3};
row = myRow;

发生的情况是,myRow在堆栈上分配,其地址存储在变量row最终导致如下情况:

| row |         |x|x|x|x|x|x|x|
|
--> |y|y|y|y|y|y|y|

因此,您丢失了对堆上数组的任何引用,row指向堆栈上的地址。您无法再删除row,退出范围时,它指向的数据将成为垃圾。你最终没有复制任何东西。

要正确复制数据,您可以使用std::copy,例如:

int myRow[] = { 1, 2, 3};
std::copy(myRow, myRow + rowSize, row);

<强制性的>

让我们看看你对其中一个元素做了什么:

matrix[2] = new int[ColSize];

matrix[2](这是一个int*(被赋予您在堆上分配的新数组的地址。

matrix[2] = matrixI2;

抛出旧的matrix[2]值(指向堆上数组的指针(,导致旧的动态分配数组丢失,并将matrix[2]指向本地数组,matrixI2

如果matrixI2超出范围,则我们的指针现在无效。此外,没有必要delete matrix[2],因为它不指向动态分配的内存。

相反,你想要的可能是:

matrix[2] = new int[12]{1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1};

对于每个索引而不是循环。