4

I have just started learning C++. I am reading the tutiorials in internet and now I made a dynamically allocated array in function.

void array_() {
    int size;
    cin >> size;

    int * Array = new int[size];


    for (int i = 0; i < size; ++i)
        cin >> Array[i];
}

How to return this function to main()

6
  • 1
    Returning the pointer? It's no difference between returning a pointer and returning an int. Commented Jun 10, 2017 at 21:59
  • 1
    @Someprogrammerdude Which happily loses the size information. Commented Jun 10, 2017 at 22:01
  • @iksemyonov True, but I'll leave that for another question... :) Commented Jun 10, 2017 at 22:02
  • First things first: how would you return an int from a function? Commented Jun 10, 2017 at 22:04
  • 1
    Don't know. Thats why I am asking you. I just want to return array to main() function. Commented Jun 10, 2017 at 22:07

4 Answers 4

12

Well, it would be wise to return the size as well as the pointer, because otherwise there'll be no way of using the resulting array safely.

So we're looking for a way to return two values from a function. This can be done by taking a reference parameter, through which you assign one of the values:

int *array_(int &size) {
    std::cin >> size;

    int *Array = new int[size];

    for (int i = 0; i < size; ++i)
        std::cin >> Array[i];

    return Array;
}

int main() {
    int size;
    int *arr = array_(size);
    // ...
    delete[] arr; // Don't forget to delete[] what has been new[]'d!
}

Or, you could return a std::pair containing both values:

std::pair<int *, int> array_() {
    int size;
    std::cin >> size;

    int * Array = new int[size];

    for (int i = 0; i < size; ++i)
        std::cin >> Array[i];

    return {Array, size};
}

int main() {
    auto arr = array_(size);
    // ...
    delete[] arr.second; // Don't forget still!
}

But both of these are crazy bad ideas, so you could start right now to write actual C++ so it doesn't look like deformed C, using standard containers:

std::vector<int> array_() {
    int size = 0;
    std::cin >> size;

    std::vector<int> vec(size);

    for(int &i : vec)
        std::cin >> i;

    return vec;
}

int main() {
    auto arr = array_(size);
    // ...
    // Now you can forget delete: no raw owning pointer, no worries.
}

Simple, leak-proof and exception-safe (well, ideally you'd sanitize user input too).

Sign up to request clarification or add additional context in comments.

2 Comments

Is RVO guaranteed to work? std::vector<T> is not a Qt-style implicit sharing class.
@iksemyonov any implementation of reasonable quality will perform NRVO here. Barring that, the vector vill be moved out of the function. In C++17 and beyond, RVO will be guaranteed by the language.
5

In C++, you can't return a variable of an array type (i.e. int arr[]) from a function "as is", though you can return a reference or a pointer to an array. That is some fairly clumsy syntax though. In the code shown, there is no array, rather a pointer to a chunk of dynamically allocated memory. The main problem however is that since the memory is dynamically allocated, when you return a pointer to that memory, you only give the client half the information: the size of the array remains unknown.

Thus, if you really want to stick to traditional arrays allocated dynamically, you can pass the size of the array as a reference parameter ("out-value") to a function like so:

int* func(std::size_t& size_out) {
    // int n = ...;
    int* array = new int[n];
    size_out = n;
    return array;
}

int main() {
    int size;
    int* result = func(size);
    delete[] result;
    result = nullptr;
}

As you can see, a side-effect of manually allocating memory is that the client takes responsibility of it, and you have to manually delete it outside of the function where it was allocated.

But "out-values" are a bad style really, especially in API's. Avoid them whenever you can!

It's of course better to use a proper dynamic array facility such as a std::vector<T>, but that seems to not be the point of the exercise.

Reference used: Return array in a function

8 Comments

Why is the first paragraph half about array decay and array pointers when there's none here, and half about saying that pointer+size array passing is somehow related to dynamic allocation, when it's not?
@Quentin Not a word about decay, since there is none in this example. There is no array. I had decay in the draft but then saw the pointer and removed it.
You didn't write the word "decay", but it's exactly the reason you can't return an actual array from a function.
@Quentin Oh do come one I just addressed what the OP said exactly. I don't think I said that returning the said pair is strictly related to dynamic memory allocation, I simply addressed the concerns in this exact post.
@zett42 True, I actually should point it out as a potential flaw in this approach.
|
4

In C++ in most cases we don't need to manually allocate resources using operator new.

I suggest to use std::vector<int> instead. It has the following advantages over a dynamically allocated plain array:

  • It will automatically deallocate the reserved memory when the scope exits (you don't have to call delete).
  • It has a size() method so you always know how many elements are contained in the vector. Compare that with a dynamic plain array where you would have to store the size in another variable.
  • You can change the size of the "array" dynamically after construction (using the resize() method for instance).

Example

std::vector<int> array_() 
{
    int size;
    cin >> size;

    // Create a dynamic "array" with the given size.
    std::vector<int> result( size );

    for (int i = 0; i < size; ++i)
        cin >> result[i];

    return result;
}

To use that "array" from main():

int main()
{
    // Call function array_() and store the result in variable v.
    std::vector<int> v = array_();

    // Print all elements of v using range-based loop.
    for( int x : v )
    {
        std::cout << x << '\n';
    }

    // Alternatively print all elements using classic loop with index.
    for( int i = 0; i < v.size(); ++i )
    {
        std::cout << v[i] << '\n';
    }
}

Comments

0

You can return the dynamically allocated array returning its pointer:

int* ProduceArray() {
    ...
    int* arrayPtr = new int[size];
    ...
    return arrayPtr;
}

However, note that in his way you loose the important information of the size of the array (which is very important for the code that consumes the array, to avoid buffer overruns).

In modern C++ a better approach is to return a standard library container like std::vector, instead of raw pointers.

Note that std::vector instances do know their size, and automatically release their memory as well (instead you must explicitly call delete[] when you have raw owning pointers).

5 Comments

"Modern" C++? Is std::vector the new hotness now? :p
"Modern" as in C++11/14/17. In C++98 there was some hesitation when returning containers, and a common practice was reference parameters. With move semantics returning potentially huge movable data is fine.
But RVO and NRVO are there since the beginning AFAIK, so there's no copy nor move in practice anyway.
RVO and NRVO were not guaranteed in all cases at least with MSVC.
Mmh, RVO issues with MSVC do ring a bell. Fair enough then :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.