C ++中的二维数组构造混淆

时间:2015-11-30 15:23:46

标签: c++ arrays

我正在为一个正在上课的实验室工作,我正在阅读老师提供的代码......我想知道这里有没有人能理解这个数组结构(这与我们完全无关程序的其余部分,所以不,你没有为我做功课:)

float **b = new float*[n]; //create local matrix
b[0] = new float[n*nCols];
for (int j = 1; j < n; j++) b[j] = b[j-1] + n;

对我来说,看起来这会在创建b之前根据内存中的内容创建一堆垃圾......没有b[0][0]的初始化,所以看起来这会产生不可预测的输出。 / p>

这是对的吗?

另外,据我所知,这是b数组指针数组的“形状”:

b= {
     *{ ?, ?, ?, ?, ?, ?, ?, .... nCols unknown floats },
     *{ ?, ?, ?, ?, ?, ?, ?, .... nCols unknown floats },
     *{ ?, ?, ?, ?, ?, ?, ?, .... nCols unknown floats },
     *{ ?, ?, ?, ?, ?, ?, ?, .... nCols unknown floats },
     *{ ?, ?, ?, ?, ?, ?, ?, .... nCols unknown floats },
     ...
     n
   }

所以b是一个大小为n的数组,指向大小为nCols的数组

这是对的吗?

这段代码看起来不应该比应该更混乱,而且可能不正确(因为它使用的是默认初始化的垃圾值)?

我是C ++的新手,我只是想确保我理解我在这里读到的东西。老师习惯了Fortran,我们正在学习并行系统,所以这与课程没有关系。

感谢。

编辑(更新)

user2079303指出这一行: for (int j = 1; j < n; j++) b[j] = b[j-1] + n; (应该是: for (int j = 1; j < n; j++) b[j] = b[j-1] + nCols;

b[x]设置为x > 0,作为指向n*nCols矩阵中元素的指针数组(存储在地址b[0]),方法是使用{{ 1}} ...

这对我来说很有意义,为什么这只是这个数组中的垃圾。所有这些构造都在创建一堆指向内存空间的指针,稍后将使用。

事实上,正如user2079303所推测的那样,在设置数据之前,不会从这些指针中读取数据,但是其他进程: b[j-1]

在该函数中,指向MPI_Scatter(a[0],n*nCols,MPI_FLOAT,b[0],n*nCols,MPI_FLOAT,0,MPI_COMM_WORLD);的指针是接收缓冲区!因此垃圾被覆盖,而不是被使用,但指针在缓冲区被覆盖后用于以后的读取是有用的。

谢谢大家。

4 个答案:

答案 0 :(得分:2)

  

对我来说,看起来这会在创建b之前根据内存中的内容创建一堆垃圾......

正确,数组中float s的值未初始化。

  

没有初始化b [0] [0]

b[0][y]中所有y的{​​{1}}均未初始化。

  

所以看起来这会产生不可预测的输出。

仅在您使用它们之前未初始化这些值。您显示的代码中根本没有输出。实际上,在显示的代码中甚至没有读取这些值。

嗯,原始代码中似乎有一个拼写错误:

[0,n*nCols)

应该是

b[j] = b[j-1] + n;

假设错误已修复,代码是正确的。否则,如果b[j] = b[j-1] + nCols; 大于n,则会出现缓冲区溢出。

  

所以b是一个大小为n的指针数组,指向大小为nCols

的数组

不完全。 nCols指向包含所有b[0]值的数组。 n*nCols中的b[x]x的其余部分指向同一数组的不同位置。但实际上,您可以使用指针,就好像它们指向大小为[1,n)的数组。

答案 1 :(得分:2)

代码既令人困惑,也可能(很难说出意图)不正确。

// we create an arry of float*
float **b = new float*[n];

// assume n is 3
//    b[0] is a float*, value not explicitly set
//    b[1] is a float*, value not explicitly set
//    b[2] is a float*, value not explicitly set

// b[0] then creates an array of float, assume nCols is 2
b[0] = new float[n*nCols]; 

//    b[0] is a float*, pointing to an array of 6 (3*2) floats
//    b[1] is a float*, value not explicitly set
//    b[2] is a float*, value not explicitly set

// we then iterate the rest and assign values (apparently incorrectly)
for (int j = 1; j < n; j++)
{
    // b[1] = b[1-1] + 3
    b[j] = b[j-1] + n;
}

在C ++中执行此操作的规范方法是使用std::vector

std::vector<std::vector<float>> matrix;

matrix.resize(n);  // resize to the number of rows

for(auto& row : matrix)
{
    row.resize(nCols);  // resize each row to the number of columns
                        // std::vector::resize will default initialize
                        // the floats created here
}

现在您可以按预期访问它:

matrix[2][1] = 6;

在这种情况下,内存布局是非连续的,对于大型矩阵来说可能很麻烦,因为需要从可能不在高速缓存中的内存中提取不同的部分。它基本上看起来像这样 - &#34;地址&#34;只是在那里表明一行中的每个值是连续的,并且每列是连续的,但是整个结构都没有断开连接。

matrix[0] - some address, assume 0
   row[0] - some address, assume 64
   row[1] - some address, assume 72
   row[2] - some address, assume 80
matrix[1] - some address, assume 8
   row[0] - some address, assume 128
   ...
matrix[1] - some address, assume 16
   row[0] - some address, assume 256

对于真正的矩阵(其中行和列都是固定的),您可以使用单个向量并使用乘法来获取/设置适当的值。

2 * 3矩阵将有6个元素。

  std::vector<float> matrix(6);  // create a vector with 6 floats

  size_t row = 1, col = 2;
  matrix[row*col] = 3;

在这种情况下,所有数据都保存在连续的内存中。

答案 2 :(得分:1)

很难通过这段代码来预测老师的意图。以下是关于可帮助您理解的数组的一些想法。

动态数组与指针无法区分。指针指向内存地址。动态数组是指向数组开头的指针,以及相关的长度(您必须知道并保留在某处)。

在您提供的代码示例中,您拥有:

float **b = new float*[n];

您正在定义一个新的内存数组。数组的大小(以字节为单位)是float*(指向浮点的指针)的大小n,并且该数组的地址存储在b中,它可以保存地址浮点指针。新阵列的所有位置都没有被初始化,并且如你所提到的那样包含垃圾。

之后你所拥有的地方:

b[0] = new float[n*nCols];

那里发生的事情是你要求一个新的内存数组。这个新数组的大小(以字节为单位)是floatn*nCols的大小,该数组的地址存储在b[0]中。这个新阵列的所有位置都没有初始化。

最后,提供的其余代码使用先前初始化位置的值初始化b的其余位置。因此,b[1]被初始化为依赖于b[0]的内容,b[2]被初始化为依赖于b[1]的内容,依此类推。

for (int j = 1; j < n; j++) b[j] = b[j-1] + n;

现在让我们深入了解一下。 b[j-1] + n正在将整数值n添加到b[j-1]类型的表达式float*中。向内存地址添加整数时,基本上定义一个新的内存地址,该地址指向原始内存地址加上整数值乘以指针大小。这被称为指针算术。

b[1] = b[0] + n

这会在b[1]中为b[0]数组中的一个移位部分指定。所以基本上b[1][X] == b[0+n][X]对于X的任何值都是正确的。这是事实,因为b[1]指向的内存地址与b[0+n]相同。

我不知道你教授提供的代码是否正确。我们需要整个代码和问题的描述正在解决。您提供的代码片段只创建了2个数组,并初始化了其中的1个数组。第二个(大型浮点数)仍未使用此代码初始化。

希望这有助于您理解。

答案 3 :(得分:0)

代码非常好,但是有点令人困惑。你的老师没有为每个子阵列进行分配调用,而是分配了一次内存并将其分配到不同的行中。

你创建的b的形状很好,但是分配的内存包含垃圾。要将其初始化为零,您可以执行以下操作,

float **b = new float*[n]; //create local matrix
b[0] = new float[n*nCols](); // this line changed
for (int j = 1; j < n; j++) b[j] = b[j-1] + n;

或者您可以使用以下内容初始化默认值

var str = new String('A string');