How to pass pointer to function and dynamically allocate memory within function C++

Parameter double *xis a local variable of function alloc_mem. When the function will end its execution the variable will be destroyed. The original variable X in main knows nothing what was done with this parameter because it was passed by value that is a copy of it was used in the function.

Either pass the pointer by pointer or by reference. For example

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;
}

As for me I would define the function the following way

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

   x = new double [size];

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

   return x;
}

if size is known before calling the function then it could be written even simpler

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

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

   return x;
}

Take into account that loop

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

can be substituted for standard algorithm std::iota For example

std::iota( x, x + size, 0.0 );

The standard C++ mechanism for defining an allocation function is operator new.

That's why the standard calls it an allocation function.

Note that operator new is different from a new-expression.

A new-expression uses the relevant allocation function (operator new function) to allocate memory, and the relevant constructor to then initialize.

However, in your case you're using (your named) allocation function just to allocate and initialize a dynamic array. Allocation and initialization are well separated responsibilities in the standard C++ language design, for very good reasons, and it would be a good idea to follow that convention. Use std::vector for your array, and if you really really really need custom allocation (very doubtful that you do), then use a custom allocator for that std::vector.


Concrete example.

Replace your current code

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;
}

with

#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;
    }
}

When you have an output parameter, you can pass it by reference, or by pointer.

For your size parameter, you passed by reference (since it's an out parameter).

The other parameter is a double*, so either add a reference:

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

or add another pointer (i.e. another level of indirection):

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

For coherence, since you used the reference (&) technique for size, I'd suggest to use it for x as well (as in (1)).

Note also that in C++ you may want to just pass a std::vector, which knows its own size, and does automatic cleanup (thanks to its destructor):

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

Note also that you may want to return the vector as a return value as well (simplifying your code):

std::vector<double> alloc_mem()

Code snippets:

// 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;    
}