6

我正在尝试声明一个指针并将该指针传递给分配内存的函数。这是一个最小的例子:

#include <string>
#include <iostream>

using namespace std;

void alloc_mem(int &size, double *x);

int main()
{

        double *X;
        int imax;

        alloc_mem(imax, X);

        cout << "imax = " << imax << endl;
        for (int i = 0; i < imax; i++) {
                cout << "X = " << X[i] << endl;
        }

        delete[]X;
        return 0;

}

void alloc_mem(int &size, double *x)
{

        size = 10;
        x = new double[size];
        for (int i = 0; i < size; i++) {
                x[i] = (double)i;
        }

}

这段代码可以编译,但是当我尝试打印 X 的值时出现分段错误。我知道我没有正确地将变量传递给函数,但我不知道该怎么做。我相信我正在对 x 的副本进行操作。

此外,编写此代码是为了重现我在更大代码中遇到的问题。

4

3 回答 3

18

参数double *x是函数 alloc_mem 的局部变量。当函数结束执行时,变量将被销毁。main 中的原始变量 X 对这个参数做了什么一无所知,因为它是通过值传递的,该值是函数中使用的它的副本。

通过指针或引用传递指针。例如

void alloc_mem(int &size, double **x);

void alloc_mem(int &size, double * &x);

void alloc_mem(int &size, double **x) 
{
   size = 10;

   *x = new double [size];

   for ( int i = 0; i < size; i++ ) ( *x )[i] = i;
}

void alloc_mem(int &size, double * &x) 
{
   size = 10;

   x = new double [size];

   for ( int i = 0; i < size; i++ ) x[i] = i;
}

至于我,我会通过以下方式定义函数

double * alloc_mem( int &size ) 
{
   size = 10;

   x = new double [size];

   for ( int i = 0; i < size; i++ ) x[i] = i;

   return x;
}

如果在调用函数之前知道大小,那么它可以写得更简单

double * alloc_mem( int size ) 
{
   x = new double [size];

   for ( int i = 0; i < size; i++ ) x[i] = i;

   return x;
}

考虑到那个循环

   for ( int i = 0; i < size; i++ ) x[i] = i;

可以代替标准算法std::iota例如

std::iota( x, x + size, 0.0 );
于 2014-04-18T15:17:39.730 回答
4

用于定义分配函数的标准 C++ 机制是operator new.

这就是标准将其称为分配函数的原因。

请注意,这与 - 表达式operator new不同new

A new-expression 使用相关的分配函数(operator newfunction)分配内存,然后使用相关的构造函数进行初始化。

但是,在您的情况下,您使用(您命名的)分配函数只是为了分配和初始化一个动态数组。分配和初始化在标准 C++ 语言设计中是完全分开的职责,有很好的理由,遵循该约定将是一个好主意。用于std::vector你的数组,如果你真的真的需要自定义分配(你很怀疑),那么使用自定义分配器std::vector


具体例子。

替换您当前的代码

int main () { 

// Declaring variables
double* X;
int imax;

// Calling function
alloc_mem(imax,X);

// Printing
cout << "imax = " << imax << endl;
for (int i=0; i<imax; i++) {
    cout << "X = " << X[i] << endl;
}

#include <vector>

int main() {
    int const imax = whatever();
    std::vector<double> X( imax );

    cout << "imax = " << imax << endl;
    for (int i=0; i<imax; i++) {
       X[i] = i;  // If you really want these values in the vector.
       cout << "X = " << X[i] << endl;
    }
}
于 2014-04-18T15:23:41.610 回答
2

当你有一个输出参数时,你可以通过引用指针传递它。

对于您的size参数,您通过引用传递(因为它是一个输出参数)。

另一个参数是 a double*,所以要么添加一个引用:

void alloc_mem(int & size, double* & x)  // (1)

或添加另一个指针(即另一个间接级别):

void alloc_mem(int & size, double** x)   // (2)

为了连贯性,由于您对 使用了参考 ( &) 技术size,我建议也使用它x(如 (1) 中所示)。

另请注意,在 C++ 中,您可能只想传递 a std::vector,它知道自己的大小,并进行自动清理(感谢它的析构函数):

void alloc_mem(std::vector<double> & x)

另请注意,您可能还希望将向量作为返回值返回(简化代码):

std::vector<double> alloc_mem()

代码片段:

// Note: the caller must free the memory using delete[].
void alloc_mem(int& size, double*& x) {
    size = 10;
    x = new double[size];
    for (int i = 0; i < size; i++) {
        x[i] = i;
    }
}

// Note: automatic vector cleanup. No need of manual delete.
std::vector<double> alloc_mem() {
    const int size = 10;
    std::vector<double> x(size); // size is 0
    for (int i = 0; i < size; i++) {
        x[i] = i;
    }
    return x;    
}
于 2014-04-18T15:27:17.653 回答