为什么顶级代码工作而底部代码不在c ++中用于动态矩阵分配?

时间:2013-05-15 07:31:23

标签: c++ dynamic-memory-allocation

我已经摆脱了那些有用的代码,因为它们让人分心。 我要做的是为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 After When Trying 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]

1 个答案:

答案 0 :(得分:2)

说明:

  • 使用delete []不释放已分配的内存。那是非常糟糕的做法总是应该记住释放你分配的内存。

  • 长期使用锯齿状阵列(阵列阵列)非常非常不舒服。更简单的解决方案是分配单个数组:

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

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

    phy[y * xlength + x] = 20.0;
    

    分配花费的时间更少,你可以免费获得的东西少得多(只有phi本身),而且访问时间也同样快。

  • 考虑使用std::vectorstd::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)组织,切片包含行(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) =第0行的第z个切片。最后,当您对数组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]展平您的数组和地址,或使用锯齿状的std::vectorstd::array s。