-6

我已经摆脱了那些会分散注意力的代码。我要做的是为 3D 数组分配一块内存。我可以简单地将分配作为锯齿状数组进行,但执行连续块更有效。

这是我当前的代码片段:

//Creating an array of proper size
//I first create an array of pointers
phi = new double**[xlength];
//I then create another array of pointers
phi[0] = new double*[xlength*ylength];
//At this point, I assume phi[0] and phi[0][0] have the same location. Is this not true?
phi[0][0] = new double[xlength*ylength*tlength];
//Now, I allocate the big block of data that will actually store my data
//I assume phi[0][0][0] has the same location as phi[0][0]. Is this right?
//Now, I'm trying to setup the pointers to match up in the single block of memory
    for (int i=0;i<xlength;i++)
    {
        for (int j=0;j<ylength;j++)
        {
            phi[i][j] = phi[0][0] + tlength*ylength*i + tlength*j;
        }
    }
//Does this not work? It feels as though it SHOULD

添加回工作代码,因为答案取决于工作代码

double*** A = new double**[m];
double**  B = new double*[m*n];
double*   C = new double[m*n*o];
for (int i=0; i<m; i++) {
    for (int j=0; j<n; j++) {
        B[n*i+j] = C + (n*i+j)*o;
    }
    A[i] = B + n*i;
}
for (int i=0; i<m; i++) {
    for (int j=0; j<n; j++) {
        for (int k=0; k<o; k++) {
            A[i][j][k] = <my_value>;
        }
    }

这是解决方案的家伙!

不要做3D矩阵,哈哈!这是我有史以来最不受欢迎的帖子!

做一个 1D 矩阵并按照这个链接上的答案C++ Segmentation Fault AfterWhen Try to Write to Matrix

这是该链接的重要部分:

但是你不能使用 phi[i][j][k] 符号,所以你应该

#define inphi(I,J,K) phi[(I)*xlength*ylength+(J)*xlength+(K)]

和写inphi(i,j,k) instead of phi[i][j][k]

4

1 回答 1

2

评论:

  • 您不会使用 delete[] 释放分配的内存。这是一个非常糟糕的做法。你应该永远记得释放你分配的内存。

  • 长期使用选择锯齿状数组(array of arrays)是非常非常不舒服的。更简单的解决方案是分配一个数组:

    double * phi = new double[xlength * ylength];
    

    然后访问 (x, y)-th 元素,如下所示:

    phy[y * xlength + x] = 20.0;
    

    分配花费的时间更少,您可以释放的东西更少(只有 phi 本身),访问时间也更快。

  • 考虑使用std::vectoror std::array。由于您使用 C++ 而不是 C,因此自然的方法是使用这些容器而不是原始数组,它们更易于管理,并且如果静态分配,它们会自行释放其内容。在您的情况下,它看起来像:

    #include <vector>
    
    (...)
    
    std::vector<std::vector<double> > phi;
    
    phi.resize(xlength);
    for (int x = 0; x < xlength; x++)
        phi[x].resize(ylength);
    

解决方案:

你的解决方案行不通。原始代码的作者使用三个变量的原因是,其中一个必须包含实际数据,另外两个用作指向原始数据部分的指针。

在您的情况下,您尝试将数据和指向数据部分的指针都保存在同一个数组中,这根本行不通。如果你想要这个[][][]符号,你必须在嵌套循环中分配锯齿状数组,就像我在我的解决方案中展示的那样。另一方面,如果您希望一个数组保留单个数据块而另一个数组保留指针,则必须像第一段代码的作者那样做。


我花了几分钟的时间才弄清楚,三个变量的三维解决方案实际上是如何工作的,所以我给大家解释一下,谁会遇到这个线程。

一般的想法是有一个带有实际数据的变量和两个带有一组指针的代理变量,这允许使用[][][]符号来寻址实际数据。

C 包含实际数据,因此它的大小为[zDim * yDim * xDim]。您可以(x, y, z)通过寻址来访问元素[z * xDim * yDim + y * xDim + x][][][]表示法表示,数据由切片 (z) 组织,切片 (z) 包含行 (y),其中包含元素 (x)。

您构造数组 B 包含指向所有行的指针,按切片排序。所以 B 包含:(slice 0, row 0), (slice 0, row 1), ..., (slice 0, row yDim - 1), (slice 1, row 0), ...

然后,构建包含指向数组 B 元素的指针的数组 A,使得 A 的第 z 个元素指向(z * yDim)= 第 z 个切片的第 0 行。最后,当您寻址数组 A 时,它的工作方式如下:

  • A[z]包含指向数组 B 元素的地址,其中包含指向第 z 个切片的第 0 行的指针
  • A[z][y]移动这个指针,这样现在我们就有了指向第 z 个切片的第 y 行的第 0 个元素的实际指针。
  • 最后,A[z][y][x]将我们移动 x 个元素,以便我们接收第 z 个切片的第 y 行的第 x 个元素。

现在应该清楚了,为什么需要附加变量以及为什么不能仅使用单个变量来完成。

底线:永远不要使用这样的解决方案,它会浪费大量内存。相反,通过[z * xDim * yDim + y * xDim + x]或使用 jagged std::vectors 或std::arrays 来展平您的数组和地址。

于 2013-05-15T07:41:25.783 回答