将指针传递给函数进行删除的正确方法是什么?

时间:2011-08-19 18:47:04

标签: c++ memory-management

我有一个声明为int **matrix的矩阵,我知道将它传递给一个分配内存的函数的正确方法应该是这样的:

void AllocMat(int ***mat, int size);

但是现在我需要在另一个函数中删除这些内存并且不确定要传递什么:

void DeallocMat(int **mat, int size);

void DeallocMat(int ***mat, int size);

我认为第二个应该是正确的,但是当我尝试时,两种方式都没有给我分段错误。

7 个答案:

答案 0 :(得分:4)

首先是正确的。但是你真正的问题是,当有更好的选择时,你正在使用指针。对于2d矩阵,您应该使用向量矢量

#include <vector>

typedef std::vector<std::vector<int> > Matrix;

Matix m;

现在没有必要删除任何东西,所以少出错。

答案 1 :(得分:4)

问题是标记为C ++,但答案仅使用C子集......

嗯,首先,我会建议反对整个事情。创建一个封装矩阵的类并将其分配到一个块中,提供operator()(int,int)以获取对元素的访问权...

但回到问题所在。在C ++中,您应该使用引用而不是指针来允许函数更改参数,因此您的原始分配签名应该是:

void AllocMat(int **&mat, int size);

并称之为:

int **matrix = 0;
AllocMat( matrix, 5 );

或者更好,只需返回指针:

int **AllocMat( int size );
int **matrix = AllocMat( 5 );

对于释放函数,由于您不需要修改外部指针,您可以使用:

void DeallocMat( int**mat, int size ); // size might be required to release the 
                                       // internal pointers

现在,有关C ++解决方案的草图:

template <typename T>                   // no need to limit this to int
class square_matrix {
   const unsigned size;
   T * data;
public:
   square_matrix( unsigned size ) : size(size), data( new T[size*size]() ) {}
   square_matrix( matrix const & m ) : size( m.size ), data( new T[m.size*m.size] ) {
      std::copy( m.data, m.data+size*size, data );
   }
   ~matrix() {
      delete [] data;
   }
   T const & operator()( unsigned x, unsigned y ) const {
      // optional range check and throw exception
      return data[ x + y*size ];
   }
   void set( unsigned x, unsigned y, T const & value ) {
      // optional range check and throw exception
      data[ x + y*size ] = value;
   }
};

答案 2 :(得分:3)

void DeallocMat(int **mat, int size) - 允许您释放内存(因为您已经传递了mat的值,只允许释放内存但不能更改mat

void DeallocMat(int ***mat, int size) - 允许您释放内存并将mat的值更改为NULL(因为您现在已经传递了指向mat的指针,允许您更改其值)

答案 3 :(得分:1)

额外的“*”只是处理指针,表现为通过引用调用。如果要从函数中获取输出,则需要在声明中添加额外的“*”。在这种情况下,您应该将指针的引用(使用&amp;)传递给这些函数。

答案 4 :(得分:0)

无论哪种方式都有效,但如果您将指针传递给指针,则需要先取消引用它。 size参数是多余的。

void DeallocMat(int **mat)
{
    delete[] mat;
}

void DeallocMat(int ***mat)
{
    delete[] *mat;
    *mat = NULL;
}

答案 5 :(得分:0)

您需要将指针传递给双指针的原因,因为您的局部变量必须反映新的更新内存

void Foo(int * a)
{
   a = new int[10];
}
int main()
{
   int *a = 0;
   Foo( a );
}

现在将分配内存,但指针A不会被更新,因为指针A的值只是复制到另一个指针变量,它是Foo的参数。一旦返回Foo,a将保持为0.为了使它反映出来,你应该编写如下代码

void Foo(int ** a)
{
   *a = new int[10];
}
int main()
{
   int *a = 0;
   Foo( &a );
}

这里你传递的是指针的地址。这意味着,指针中包含的值将从Foo函数更新。您可以调试并查看它是如何工作的。

如果您确定不再访问指针,请使用第一种类型。否则使用第二个。确保将指针设置为NULL以避免进一步的内存损坏或悬空指针。

答案 6 :(得分:0)

让我对你的问题感到困惑的是,大多数人都不会将矩阵声明为int **。这样做的原因是你将被迫在循环中分配它。你的分配函数需要两个参数,就是这个数组的维度:

void AllocMat(int *** mat, int n, int m) {
    int ** result = new int * [ n ];
    for (int x=0; x<n; x++) {
        result[x] = new int [ m ];
    }
    *mat = result;
}

如果是这种情况,相应的释放函数需要知道n的大小如下:

void DeallocMat(int *** mat, int n) {
    if (mat == NULL || *mat == NULL) return;
    int ** tmp = *mat;
    for (int x=0; x<n; x++) {
        if (tmp[x] != NULL) delete [] tmp[x];
    }
    delete [] tmp;
    *mat = NULL;
}

使用这种方法,您可以像这样访问矩阵:

int ** mat = NULL;
AllocMat(&mat, n, m);

for (int x=0; x<n; x++) {
    for (int y=0; y<m; y++) {
        mat[x][y] = 1;
    }
}

DeallocMat(&mat, n);

通常,人们将矩阵分配为单个内存缓冲区,以避免额外的分配和指针间接,这就是我建议你这样做的方法。在这种情况下,您的分配函数将如下所示:

void AllocMat2(int ** mat, int n, int m) {
        *mat = new int [ n * m ];
}

相应的释放函数如下:

void DeallocMat2(int ** mat) {
    if (mat != NULL && *mat != NULL) {
        delete [] *mat;
        *mat = NULL;
    }
}

您可以访问以下内容:

int * mat2 = NULL;
AllocMat2(&mat2, n, m);

for (int x=0; x<n; x++) {
    for (int y=0; y<m; y++) {
        mat2[x * n + y] = 1;
    }
}

DeallocMat2(&mat2);