4

I have been working on a function that accepts an array and an array size as an argument. The functions task is to create a second array that is twice the size of the fist array, copying the elements of the first array into the first half of the second array, and initializing the remaining elements to zero.

I can only get this to work if I dynamically allocate the second array with in the function. I suspect this is because once a function returns control to the calling function, any array that is not dynamically allocated is deleted from memory. In other words, the pointer in the calling function will point to junk data because the second array that was created in the expander function is now gone. Can anyone confirm this?

Here is the function written two different ways.

This way works

int *array_expander(int array[], int size)
{

    int *new_array = new int[size*2];

    for(int i{0}; i < size; i++)
        *(new_array + i) = *(array + i);

    for(int i{size}; i < size * 2; i++)
        *(new_array + i) = 0;

    return new_array;
}

This way doesn't

int *array_expander(int array[], int size)
{
    int new_array[size * 2];

    for(int i{0}; i < size; i++)
        *(new_array + i) = *(array + i);

    for(int i{size}; i < size * 2; i++)
        *(new_array + i) = 0;

    int *arr_ptr = new_array;

    return new_array;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Tcrumb
  • 53
  • 3
  • 5
    Yes, you understand it correctly. – HolyBlackCat Dec 05 '19 at 21:22
  • 1
    Correct. And that's, as one of my teachers used to say, "The worst kind of garbage: garbage that looks good." – benbotto Dec 05 '19 at 21:24
  • 1
    Does this answer your question? [How to return local array in C++?](https://stackoverflow.com/questions/7769998/how-to-return-local-array-in-c) – Algirdas Preidžius Dec 05 '19 at 21:24
  • 5
    Not to mention, the fact, that `int new_array[size * 2];` is non-standard C++, due to it being VLA (variable length array), which is not supported by C++ standard, but, probably, enabled by compiler extension. – Algirdas Preidžius Dec 05 '19 at 21:25
  • 1
    As @AlgirdasPreidžius pointed out, `int new_array[size*2];` is not standard C++, so if your input has already variable length, you should move to `std::vector` since `int array[size];` is not allowed if `size` is not a compile-time constant. If it is, you could think about using `std::array` which is basically a wrapper around `int[N]` and which can be returned by functions. The you would have to template your function. – n314159 Dec 05 '19 at 21:28
  • 1
    `int *array_expander(int array[], int size)` - why not change that to take a `std::array` or `std::vector`? Both of those know their `.size()` and are superior to C-style arrays in every way. Don't use C-style arrays in C++.. – Jesper Juhl Dec 05 '19 at 22:01

2 Answers2

5

You are right. You may not return a pointer to a local object with the automatic storage duration from a function because the returned pointer will be invalid due to the fact that the local object will not be alive after exiting the function.

Moreover variable length arrays is not a standard C++ feature. So this statement

int new_array[size * 2];

can not be compiled by a compiler that does not have its own corresponding language extension.

As for the function then it should be declared like

int * array_expander( const int array[], size_t size );

You should add the qualifier const to the first parameter because the passed array is not changed in the function.

The function can be implement by using standard algorithms as it is shown in the demonstrative program below.

#include <iostream>
#include <algorithm>

int * array_expander( const int array[], size_t size )
{
    int *new_array = new int[ 2 * size ];

    std::fill_n( std::copy( array, array + size, new_array ), size, 0 );

    return new_array;
}

int main() 
{
    int a[] = { 1, 2, 3, 4, 5 };
    const size_t N = sizeof( a ) / sizeof( *a );

    for ( const auto &item : a ) std::cout << item << ' ';
    std::cout << '\n';

    int *new_array = array_expander( a, N );
    size_t n = 2 * N;

    for ( size_t i = 0; i < n; i++ ) 
    {
        std::cout << new_array[i] << ' ';
    }
    std::cout << '\n';

    delete [] new_array;

    return 0;
}

The program output is

1 2 3 4 5 
1 2 3 4 5 0 0 0 0 0 

Pay attention to that instead of arrays you could use the standard container std::vector.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    "instead of arrays you could use the standard container std::vector" - or `std::array` if the array is of fixed size. – Jesper Juhl Dec 05 '19 at 22:06
2

Some compilers allow you to do that, but most compilers don't. This is because when you create an array using:

int arr[10];

The '10' here is a 'const int'. To create the array statically, the size given must be a constant integer. Equivalently, you can also do this:

const int size = 10;
int arr[size];

But if you try this:

int size;
cin >> size;
int arr[size]; // Illegal

You can see that the size is not predefined, and varies on user input. This will not work. This why we use dynamic memory allocation. We need to do this:

int size;
cin >> size;
int *arr = new int[size]; // You can use it like an array now!

I hope this helps! :-)

Ali Sajjad
  • 3,589
  • 1
  • 28
  • 38