3

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()

KonradDos
  • 241
  • 2
  • 3
  • 11

4 Answers4

10

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).

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • Is RVO guaranteed to work? `std::vector` is not a Qt-style implicit sharing class. – iksemyonov Jun 10 '17 at 23:16
  • @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. – Quentin Jun 10 '17 at 23:23
4

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

colossatr0n
  • 2,215
  • 1
  • 12
  • 18
iksemyonov
  • 4,106
  • 1
  • 22
  • 42
  • 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 Jun 10 '17 at 22:18
  • @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. – iksemyonov Jun 10 '17 at 22:20
  • You didn't write the word "decay", but it's exactly the reason you can't return an actual array from a function. – Quentin Jun 10 '17 at 22:22
  • @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. – iksemyonov Jun 10 '17 at 22:30
  • @zett42 True, I actually should point it out as a potential flaw in this approach. – iksemyonov Jun 10 '17 at 22:34
  • Well alright, I get what you mean. But still, "since the memory is dynamically allocated" is misleading: the issue would be identical with, for example, a `static` array. – Quentin Jun 10 '17 at 22:40
  • @Quentin You're right, it's unfortunate effect of I how I worded it, perhaps. Really, was trying to address just what the OP was asking about. Now mine is accepted and better answers are not. :\ – iksemyonov Jun 10 '17 at 23:02
  • `std::array` would be the proper array c++ syntax sugar to directly replace traditional c raw array syntax. `std::vector` is a different sort of data structure [a very close relative]. `std::array` has the same runtime behavior and performance as a raw array. (`std::array` literally gets converted to a raw array during compile.) – Max Power Feb 20 '22 at 05:13
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';
    }
}
zett42
  • 25,437
  • 3
  • 35
  • 72
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).

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • "Modern" C++? Is `std::vector` the new hotness now? :p – Quentin Jun 10 '17 at 22:15
  • "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. – Mr.C64 Jun 10 '17 at 22:19
  • 1
    But RVO and NRVO are there since the beginning AFAIK, so there's no copy nor move in practice anyway. – Quentin Jun 10 '17 at 22:20
  • RVO and NRVO were not guaranteed in all cases at least with [MSVC](https://msdn.microsoft.com/en-us/library/ms364057(v=vs.80).aspx). – Mr.C64 Jun 10 '17 at 22:21
  • Mmh, RVO issues with MSVC do ring a bell. Fair enough then :) – Quentin Jun 10 '17 at 22:23