我正在为一个正在上课的实验室工作,我正在阅读老师提供的代码......我想知道这里有没有人能理解这个数组结构(这与我们完全无关程序的其余部分,所以不,你没有为我做功课:)
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);
的指针是接收缓冲区!因此垃圾被覆盖,而不是被使用,但指针在缓冲区被覆盖后用于以后的读取是有用的。
谢谢大家。
答案 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];
那里发生的事情是你要求一个新的内存数组。这个新数组的大小(以字节为单位)是float
次n*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');