0

I am trying to learn on how you can return pointers to arrays, so that you can go around the whole "you can't return arrays in C/C++"-Problem.

I am a beginner in C++, but I know a lot about Java if that helps.

My code is this:

// Source.cpp

#include <iostream>

// Returns a pointer to an array that contains the digits 0 to 9.
int* test()
{
    // Create the array.
    int r[10] = {0,1,2,3,4,5,6,7,8,9};
    
    // Return the address to the array.
    return r;
}

// Simple function that takes an "pointer" array or a "normal" array and prints the elements of them.
void print_arr(const int arr[], const int length)
{
    for (int i = 0; i < length; i++)
        std::cout << i << ": " << arr[i] << std::endl;
    
}


int main()
{
    // Test the printing function with an "normal" array containing the digits 0 to 9.
    print_arr(new int[10] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 10);
    // Insert a line break to make the output look more clean.
    std::cout << std::endl;
    // Print the "pointer" array that should contain the same as the temporary variable.
    print_arr(test(), 10);
}

My output is this on the default "Debug" configuration in VS22: (language standard: ISO C++ 14, Windows SDK Version: 10.0, Platform Toolset: Visual Studio 2022 (v143))

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

0: 529054832
1: 32759
2: 2
3: 3
4: 4
5: 5
6: 6
7: 7
8: 8
9: 9

My output is this on the default "Release" configuration in VS22: (language standard: ISO C++ 14, Windows SDK Version: 10.0, Platform Toolset: Visual Studio 2022 (v143))

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

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

I have simelar issues with the Debug configuration changing values magically in visual studio. In general I have no idea what differences are there between these two configurations. I look forward for some tips with the Visual Studio Coding enviroment in general :).

I tried giving the "pointer" array an offset of it's adress in line 10 by just adding 2 (return r + 2;), which worked, but of course that only changed the adress and not the contents of the array in the memory, so the outputs of the second print_arr were the digits from 2 to 9:

0: 2
1: 3
2: 4
3: 5
4: 6
5: 5
6: 8
7: 9
8: -858993460
9: -858993460

As I said, it "magically" (for me) works by changing to the "Release" config.

  • 4
    Just use `std::array` and problem of returning it from a function vanishes. Available since C++11 and should be preferred over C-style arrays. If array has dynamic size use `std::vector`. – Marek R Apr 26 '23 at 11:57
  • Thank you for the recommendation :), but with this practice I am also trying to make the whole array pointers thing make sense in my head. – Henri Heyden Apr 26 '23 at 12:00
  • 3
    You return dangling pointer, so you have UB. anything can happen. – Jarod42 Apr 26 '23 at 12:00
  • 4
    You should learn how to code in 2020 not how to code in 1990. – Marek R Apr 26 '23 at 12:01
  • 2
    It's about lifetime. The array in `test` is destroyed when the function exits, but you return a pointer to that array. Thereafter you use that pointer, this means your program has *undefined behaviour* because you are accessing a destroyed object. This issue does not arise in Java because Java has garbage collection, C++ does not. In C++ it's up to you to manage and be aware of the lifetime of the objects you create. – john Apr 26 '23 at 12:01
  • `std::array` is *the way*. If you want to write it your own, wrap the array in a custom class, but then you are either reimplementing `std::array` or `std::vector`. There is really not much to learn from it, other than that you should not use raw c-arrays. However, I dont want to discourage you. This is basically all you need : [`std::array`](https://en.cppreference.com/w/cpp/container/array): "This container is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member. " – 463035818_is_not_an_ai Apr 26 '23 at 12:02
  • The whole "C style"/pointers thing to arrays does not make much sense anyway (except making it easy for the compiler). In the end a "C" style array is just a pointer to the first element in the array and most of the managment is left up to you. As said better use std::array (which will have the same memory layout as a "C" style array) or std::vector. For your code to work you would need to return a pointer to (heap) allocated memory instead of returning a local variable. – Pepijn Kramer Apr 26 '23 at 12:05
  • Also don't get confused by the large amount of examples online that still use "C" style arrays. Most people learn C++ through data structure classes and never have learned proper C++. As @463035818_is_not_a_number says : std::array/std::vector are the constructs to use nowadays (std::vector has nearly been around 30 years so I am amazed it isn't used more) – Pepijn Kramer Apr 26 '23 at 12:05
  • @john so the problem is that the runtime basically detects r will not be used again, so it declares the content of r as unimportant and frees the space, and after some lines of code the original r gets overwritten? Do I have to use malloc to counter this? – Henri Heyden Apr 26 '23 at 12:07
  • @HenriHeyden It doesn't detect that `r` will not be used again (after all you did try to use it via the returned pointer). That `r` is destroyed when `test` exits is guaranteed. Using dynamic allocation, preferably with `new`, but `malloc` would also work, avoids this problem because a dynamically allocated object exists until you explicitly destroy it. – john Apr 26 '23 at 12:09
  • @HenriHeyden Compare with C++/vector/ostream overloading (instead of print function): https://onlinegdb.com/d57I0iA--r. The template makes the output usable for vectors of many types. And the range based for loop ensures you will never access the array/vector out of bounds. – Pepijn Kramer Apr 26 '23 at 12:11
  • In your function `test()` the array `r` has automatic storage duration, so ceases to exist as the function returns. The function therefore returns a dangling reference (a pointer to something [the first element of an array] that no longer exists) and *that* causes undefined behaviour. To avoid undefined behaviour, while still returning a pointer, the array must *still exist* after the function returns. Returning an `std::array` avoids undefined behaviour with cost of COPYING the entire array (the potential cost varies between C++ standards, due to evolving requirements for elision). – Peter Apr 26 '23 at 12:17
  • 2
    @HenriHeyden *but I know a lot about Java if that helps.* -- It doesn't help. Do not use or attempt to use Java as a model in writing or learning C++. – PaulMcKenzie Apr 26 '23 at 12:19
  • 2
    Incidentally, telling us you know a lot about Java doesn't achieve anything. Java and C++ are quite different languages, and - in this case - the way things work in C++ have no real counterpart in Java. – Peter Apr 26 '23 at 12:21
  • No, you should not use `malloc`. There is no valid reason for any C++ code to ever use `malloc`, for anything. `malloc` is for C code, and this is C++. Unfortunately, the technical specifications for C++ run to about two thousand pages of terse text, and attempting to learn C++ by asking one question at a time will take a very, very long time. The only practical way to learn C++ is [with a good textbook](https://stackoverflow.com/questions/388242/). – Sam Varshavchik Apr 26 '23 at 12:24
  • @HenriHeyden What you accomplished is one reason why you should use good books to learn C++, and not try to learn by "winging it" and/or use another computer language as a guide. You spent time with all of these experimentations, configuration changes in the compiler, etc. to discover something that is fundamental to C++, and that is about lifetime's of variables. Another thing that may trip you up is when you pass objects in C++, where C++ uses copy semantics to pass objects by value, way different than Java. So `foo(SomeObject x)` does *not* work the same in C++ as it would in Java. – PaulMcKenzie Apr 26 '23 at 12:41

0 Answers0