Reputation: 97
I want to make a simple function in C++ to get some practise. It should do the same thing as the range() function in python but for now a lot simpler. I ran into a problem that the array isn't returned properly from the function to the main function. I used to code below and got a weird error. Does someone know what the problem might be?
#include "iostream"
int * range(int max){
int n = 0;
int ran [max] ;
while (n < max){
ran[n] = n;
n += 1;
}
return ran;
}
int main(){
int * ranger;
ranger = range(5);
for(int k = 0; k < 5; k++){
std::cout << ranger[k] << " ";
}
return 0;
}
I didn't get an error message from the comiler it just did nothing for a few seconds and then printed out: Process finished with exit code -1073741819 (0xC0000005)
Upvotes: 0
Views: 4956
Reputation: 238311
got a weird error. Does someone know what the problem might be?
The first step of finding out the reason for a weird error is to read the error message. It often explains the reason.
How can you return an array from a function in c++
You cannot return an array from a function in C++.
You can however return a class object, and class can contain an array as a member. As such by wrapping an array in a class and returning instance of that class, you can get around the restriction. There is a generic template for such array wrapper in the standard library. It is called std::array
. std::array
is limited to compile time constant size, just like array variables (see below).
int * range(/*...*/){ // ... int ran [max] ; // ... return ran; }
The problem with this is that the array is an automatic variable. The lifetime of automatic variables end when they go out of scope. Thus, the array doesn't exist after the function returns.
Returning a pointer to an automatic variable is pointless, because the pointed object never exists outside the function. Attempting to access the object through the pointer will result in undefined behaviour. You should always avoid undefined behaviour. It is bad.
Don't forget to use compiler warnings. This is what my compiler says:
warning: address of local variable 'ran' returned [-Wreturn-local-addr] 10 | return ran; | ^~~
int * range(int max){ // ... int ran [max] ;
The size of an array variable must be a compile time constant in C++. A function parameter is not compile time constant. Thus, this program is ill-formed.
Don't forget to use compiler warnings. This is what my compiler says:
warning: ISO C++ forbids variable length array 'ran' [-Wvla] 5 | int ran [max] ; | ^~~
If you need to create a dynamic array, then you must allocate it dynamically. The simplest and the most convenient way to create a dynamic array is to use std:vector
.
It should do the same thing as the range() function in python
Note that python range doesn't return a list (since python 3). It returns a lazy generator range. This would also be the recommended approach in C++, instead of returning a vector.
Lazy ranges are a bit too advanced to implement for beginners, but instead of implementing it yourself, I recommend using the standard library:
for (int i : std::views::iota(0, 5))
std::cout << i << " ";
#include "iostream"
Minor issue: #include <iostream>
should conventionally be used with standard headers. Otherwise you may get surprising results if there happens to be a file named iostream
in your include path. That said, try to avoid having a file named iostream
in your include path as well (besides than the standard one).
Upvotes: 2
Reputation: 1258
Try to pass the array as a reference instead of returning it.
#include "iostream"
void range(int max, int* ranger){
int n = 0;
while (n < max){
ranger[n] = n;
n += 1;
}
}
int main(){
int ranger[5];
range(5, ranger);
for(int k = 0; k < 5; k++){
std::cout << ranger[k] << " ";
}
return 0;
}
Edit: As @Jarod42 pointed out, I've changed the memory allocation from int *
to int[5]
.
Upvotes: 4
Reputation: 910
I will do this way :
#include <iostream>
#include <vector>
void
range (std::vector< int > & ranger)
{
int n = 0;
while (n < ranger.size())
{
ranger[n] = n;
n += 1;
}
}
int main ()
{
std::vector< int > ranger(5);
range(ranger);
for ( auto value : ranger )
{
std::cout << value << ' ';
}
return 0;
}
Or, if you really want to return the array :
std::vector< int >
range (int max)
{
std::vector< int > ranger(max);
int n = 0;
while (n < ranger.size())
{
ranger[n] = n;
n += 1;
}
return ranger;
}
int main ()
{
auto ranger = range(5);
for ( auto value : ranger )
{
std::cout << value << ' ';
}
return 0;
}
And finally you should take a look at std::transform from to get a better approach.
Upvotes: 0
Reputation: 131445
As @eerorika says, you can't pass raw arrays in C++ by value. And while you could get around this restriction, in your specific example you can simply avoid the problem altogether. You write:
int * range(int max){
int n = 0;
int ran [max] ;
while (n < max){
ran[n] = n;
n += 1;
}
return ran;
}
this is a sort of a named constructor idiom for a range of consecutive integers, from 0 to max-1, in a raw array. But you don't actually need this array explicitly, seeing how you know what's in it. Instead, consider using std::views::iota(0,max)
.
When you want to use it, you'll probably want to iterate over the range, like so:
#include <ranges>
#include <iostream>
void foo(std::size_t max) {
using namespace std::ranges;
for (int i : views::iota_view(0, max)) {
std::cout << i << ' ';
// or any other work
}
}
See
This question: Neatest way to loop over a range of integers or more details.
Upvotes: 0