0

My question is basically a follow-up question of this question Proper way to pass dynamic arrays to other functions. Here the proper way for passing a dynamic array to a function is asked. Three options are given:

void test(bool arr[])
void test(bool *arr)
void test(bool *&arr)

The first two pass the pointer(of the array) by value and the second passes the pointer by reference. All can be used to change the content of the array as shown in alestanis' answer.

Now my question is what would be the correct way if you want to dynamically allocate the array inside the function. So something like this:

void init(double ?arr?, int n){
    arr = new double[n];
}

void main(){
    double * array;
    init(array,15);
}

I believe it works with the last syntax only, but I'm not sure.

Furthermore I would like to know how the last syntax would look like if you have a matrix. Would you have two &'s? Or is it just not possible?

P.S. I have vary large vectors and matrices so I would rather use regular array instead of std stuff. The size of the vectors and matrices are sort of input values for the user and the vectors and matrices are only created after input is complete so I never have the need to resize the vector/matrix.

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
C. Binair
  • 419
  • 4
  • 14
  • 1
    Think out of the box: use `std::vector`. The `std::vector` will handle memory allocation and deallocation for you. It has the same access operator that arrays do. You can even pass by reference if you want to modify it. – Thomas Matthews Sep 30 '19 at 16:27
  • *I have vary large vectors and matrices so I would rather use regular array instead of std stuff* - If this is performance related you are not loosing anything switching to `std::vector` if you use it properly. On the other hand you are gaining A LOT in terms of safety etc. – super Sep 30 '19 at 16:39
  • Write with `std` stuff and without. Then compile, profile and compare the results. All that should be left over of the `vector` is a tiny blip during initialization. Whether that's important or not depends on the requirements. – user4581301 Sep 30 '19 at 16:49
  • @user4581301 -- Sometimes vector improves the speed of the code, especially if the original non-vector code uses `new[]` and `delete[]` over and over again instead of one vector and doing a simple `resize()`. – PaulMcKenzie Sep 30 '19 at 17:59
  • I would prefer `double* array = make_double_array(15);` over output argument. (but even better would be `std::vector` or at least `std::unique_ptr`). – Jarod42 Sep 30 '19 at 18:14

1 Answers1

2

If you will pass a pointer by value then its changes of the pointer with the function do not influence on the original argument. The function will deal wuth a copy of the value of the original pointer.

So you have two approaches. The C++ approach is

void test(bool *&arr);

The C approach is

void test(bool **arr)

Here is a demonstrative program.

#include <iostream>
#include <iterator>
#include <numeric>

void init( double * &a, size_t n )
{
    a = new double[n];

    std::iota( a, a + n, 0.0 );
}

void init( double **a, size_t n )
{
    *a = new double[n];

    std::iota( std::reverse_iterator<double *>( *a + n ), std::reverse_iterator<double *>( *a ), 0.0 );
}

int main() 
{
    size_t n = 10;
    double *a = nullptr;

    init( a, n );

    for ( const double *p = a; p != a + n; ++p )
    {
        std::cout << *p << ' ';
    }

    std::cout << '\n';

    delete []a;
    a = nullptr;

    init( &a, n );

    for ( const double *p = a; p != a + n; ++p )
    {
        std::cout << *p << ' ';
    }

    std::cout << '\n';

    delete []a;
    a = nullptr;

    return 0;
}

Its output is

0 1 2 3 4 5 6 7 8 9 
9 8 7 6 5 4 3 2 1 0

If you want to allocate dynamically a two-dimensional array with a fixed number of columns then for example the function declarations can look the following way.

#include <iostream>
#include <iterator>
#include <numeric>

const size_t N = 5;

void init( double ( * &a )[N], size_t n )
{
    a = new double[n][N];

    for ( size_t i = 0; i < n; i++ )
    {
        std::iota( std::begin( a[i] ), std::end( a[i] ), i + i / 10.0 ); 
    }        
}

void init( double ( **a )[N], size_t n )
{
    *a = new double[n][N];

    for ( size_t i = 0; i < n; i++ )
    {
        std::iota( std::begin( ( *a )[i] ), std::end( ( *a )[i] ), i + i / 10.0 ); 
    }        
}

int main()
{
    double ( *a )[N] = nullptr;

    init( a, N );

    for ( size_t i = 0; i < N; i++ )
    {
        for ( const auto &item : a[i] )
        {
            std::cout << item << ' ';
        }

        std::cout << '\n';
    }

    std::cout << '\n';

    delete []a;
    a = nullptr;

    init( a, N );

    for ( size_t i = 0; i < N; i++ )
    {
        for ( const auto &item : a[i] )
        {
            std::cout << item << ' ';
        }

        std::cout << '\n';
    }

    std::cout << '\n';

    delete []a;
    a = nullptr;

    return 0;
}

The program output is

0 1 2 3 4 
1.1 2.1 3.1 4.1 5.1 
2.2 3.2 4.2 5.2 6.2 
3.3 4.3 5.3 6.3 7.3 
4.4 5.4 6.4 7.4 8.4 

0 1 2 3 4 
1.1 2.1 3.1 4.1 5.1 
2.2 3.2 4.2 5.2 6.2 
3.3 4.3 5.3 6.3 7.3 
4.4 5.4 6.4 7.4 8.4
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335