Return array in a function
Solution 1
In this case, your array variable arr
can actually also be treated as a pointer to the beginning of your array's block in memory, by an implicit conversion. This syntax that you're using:
int fillarr(int arr[])
Is kind of just syntactic sugar. You could really replace it with this and it would still work:
int fillarr(int* arr)
So in the same sense, what you want to return from your function is actually a pointer to the first element in the array:
int* fillarr(int arr[])
And you'll still be able to use it just like you would a normal array:
int main()
{
int y[10];
int *a = fillarr(y);
cout << a[0] << endl;
}
Solution 2
C++ functions can't return C-style arrays by value. The closest thing is to return a pointer. Furthermore, an array type in the argument list is simply converted to a pointer.
int *fillarr( int arr[] ) { // arr "decays" to type int *
return arr;
}
You can improve it by using an array references for the argument and return, which prevents the decay:
int ( &fillarr( int (&arr)[5] ) )[5] { // no decay; argument must be size 5
return arr;
}
With Boost or C++11, pass-by-reference is only optional and the syntax is less mind-bending:
array< int, 5 > &fillarr( array< int, 5 > &arr ) {
return arr; // "array" being boost::array or std::array
}
The array
template simply generates a struct
containing a C-style array, so you can apply object-oriented semantics yet retain the array's original simplicity.
Solution 3
In C++11, you can return std::array
.
#include <array>
using namespace std;
array<int, 5> fillarr(int arr[])
{
array<int, 5> arr2;
for(int i=0; i<5; ++i) {
arr2[i]=arr[i]*2;
}
return arr2;
}
Solution 4
$8.3.5/8 states-
"Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays of pointers to functions."
int (&fn1(int (&arr)[5]))[5]{ // declare fn1 as returning refernce to array
return arr;
}
int *fn2(int arr[]){ // declare fn2 as returning pointer to array
return arr;
}
int main(){
int buf[5];
fn1(buf);
fn2(buf);
}
Solution 5
the answer may depend a bit on how you plan to use that function. For the simplest answer, lets decide that instead of an array, what you really want is a vector. Vectors are nice because the look for all the world like boring, ordinary values you can store in regular pointers. We'll look at other options and why you want them afterwards:
std::vector<int> fillarr( std::vector<int> arr ) {
// do something
return arr;
}
This will do exactly what you expect it to do. The upside is that std::vector
takes care of making sure everything is handled cleanly. the downside is that this copies a very large amount of data, if your array is large. In fact it copies every element of the array twice. first it copies the vector so that the function can use it as a parameter. then it copies it again to return it to the caller. If you can handle managing the vector yourself, you can do things quite a bit more easily. (it may copy it a third time if the caller needs to store it in a variable of some sort to do more calculation)
It looks like what you're really trying to do is just populate a collection. if you don't have a specific reason to return a new instance of a collection, then don't. we can do it like this
void fillarr(std::vector<int> & arr) {
// modify arr
// don't return anything
}
this way you get a reference to the array passed to the function, not a private copy of it. any changes you make to the parameter are seen by the caller. You could return a reference to it if you want, but that's not really a great idea, since it sort of implies that you're getting something different from what you passed.
If you really do need a new instance of the collection, but want to avoid having it on the stack (and all the copying that entails), you need to create some kind of contract for how that instance is handled. the easiest way to do that is to use a smart pointer, which keeps the referenced instance around as long as anyone is holding onto it. It goes away cleanly if it goes out of scope. That would look like this.
std::auto_ptr<std::vector<int> > fillarr( const std::vector<int> & arr) {
std::auto_ptr<std::vector<int> > myArr(new std::vector<int>);
// do stuff with arr and *myArr
return myArr;
}
For the most part, using *myArr
works identically to using a plain vanilla vector. This example also modifies the parameter list by adding the const
keyword. Now you get a reference without copying it, but you can't modify it, so the caller knows it'll be the same as before the function got to it.
All of this is swell, but idiomatic c++ rarely works with collections as a whole. More normally, you will be using iterators over those collections. that would look something more like this
template <class Iterator>
Iterator fillarr(Iterator arrStart, Iterator arrEnd) {
Iterator arrIter = arrStart;
for(;arrIter <= arrEnd; arrIter++)
;// do something
return arrStart;
}
Using it looks a bit odd if you're not used to seeing this style.
vector<int> arr;
vector<int>::iterator foo = fillarr(arr.begin(), arr.end());
foo now 'points to' the beginning of the modified arr
.
What's really nice about this is that it works equally well on vector as on plain C arrays and many other types of collection, for example
int arr[100];
int *foo = fillarr(arr, arr+100);
Which now looks an awful lot like the plain pointer examples given elsewhere in this question.
Related videos on Youtube
Ismail Marmoush
You can check my website and blog https://marmoush.com
Updated on September 02, 2020Comments
-
Ismail Marmoush over 3 years
I have an array
int arr[5]
that is passed to a functionfillarr(int arr[])
:int fillarr(int arr[]) { for(...); return arr; }
- How can I return that array?
- How will I use it, say I returned a pointer how am I going to access it?
-
BuggerMe over 13 yearsstrictly speaking in this context you don't need to return the array since the array is passed by reference so any changes to elements inside 'arr' will be seen outside the function.
-
seand over 13 yearsreturning the array is convenient for chaining functions.
-
detly over 13 yearsAs long as you're not making the mistake of creating an array on the stack and returning a pointer to it.
-
Ismail Marmoush over 13 years@buggerme yes you're right , but you can consider the array returned arr2 , totally another array , my mistake sry :)
-
GManNickG over 13 years@ismail: It cannot return a new array, unless that array was dynamically allocated. And if that's the case, use
std::vector
. -
David Rodríguez - dribeas over 13 years@BuggerMe: Arrays are not passed by reference (unless you request it with a much funnier syntax), in the code, the array decays into a pointer to the first element and that is passed to the function. The
5
in the function signature is discarded by the compiler. -
BuggerMe over 13 years@David in the essence of C, when you pass arrays you always pass them by reference allowing the contents of the array to be changed. What I think you mean is passing the array ptr by reference allowing changing the ptr.
-
David Rodríguez - dribeas over 13 years@BuggerMe: Not, not really. I was being precise as I have grown used to people misunderstanding the semantics of the pass-by-value syntax for arrays in C++. Passing an array by reference is:
void foo( int (&array)[5] );
(array of 5 ints by reference). When you pass by reference what you get inside the function is a reference to the actual type. On the other handvoid foo( int array[5] )
is translated by the compiler tovoid foo(int*)
during the function definition. Callingfoo( myarray )
produces the decay of the array to a pointer to the first element. -
BuggerMe over 13 years@David sorry but a c-array is never passed by value, the only way you can do that (in C) is by putting into a struct. I agree that the pointer to the array is by value but the array itself is passed by value.
-
David Rodríguez - dribeas over 13 years@BuggerMe: Maybe I was not clear enough, I know that in C/C++, arrays are never actually passed by value. If you carefully read the comment you will see "semantics of the pass-by-value syntax". That is, the syntax is the that of pass-by-value, but the semantics are not that of pass-by-value, the language transforms that syntax into the known decayed array. This c++ discussion is extending well beyond the intended use of the comments. Google for array reference decay c++. One of the first results is this.
-
GManNickG over 13 yearsTo clarify, that "classic C++ statement" is false; arrays are not pointers.
-
seand over 13 yearsI don't think the 'int [] fillarr ...' is legal. The 'int *fillarr' is what you would use due to array-pointer equivalence.
-
seand over 13 yearsremember the a[i] == *(a + i) rule
-
Brent Writes Code over 13 yearsHow should I rephrase it? Isn't the array variable really just a constant pointer to the beginning of the memory block allocated for the array? And then the
[]
just does pointer arithmetic based off of that initial address to locate further elements in the array? -
Carl Norum over 13 years@Brent Nash, no. an array is an array. A pointer to the start of the array is a pointer. It just happens that the compiler has some syntactic sugar that does the translation for you in some situations.
array
and&array
are interchangeable in a lot of cases. -
GManNickG over 13 years@Brent: No. An array is it's own type, it's not a special kind of pointer. The type of
a
inint a[10]
isint[10]
. What you can say is arrays "decay" into pointers to their first element. (This is an implicit array-to-pointer conversion.) Then your answer would go along the lines mine does. If you edit your answer to differentiate between arrays, array-to-pointer conversion, and pointers, I'll delete my answer since they would have the same core information and you were first. -
Brent Writes Code over 13 yearsI'll leave this answer here if for no other reason than I think this comment chain has some really valuable comments. I think @Potatoswatter should probably get your vote for correct answer though. Thanks for the good comments, all.
-
GManNickG over 13 yearsUse
std::copy
overmemset
, it's safer and easier. (And just as fast if not faster.) -
GManNickG over 13 yearsYour second function returns a pointer to an
int
, not an array. -
David Rodríguez - dribeas over 13 years+1 for giving an example of how an array can be passed by reference. But you are wrong in that you cannot return an array by reference. The simplest syntax to achieve it is by using a typedef:
typedef int array[5]; array& foo();
But you don't even need the typedef if you care to write this:int (&foo())[5] { static int a[5] = {}; return a; }
, the example in the question would be:int (&foo( int (&a)[5] ))[5] { return a; }
. Simple, isn't it? -
David Rodríguez - dribeas over 13 yearsThe syntax is wrong, the
&
symbol must appear after the type:void fillarr(std::vector<int> & arr)
-
Potatoswatter over 13 years@David: thanks, I got the misimpression from the Comeau message
error: function returning array is not allowed
which occurs if you leave out the outer parens in the non-typedef syntax. Fortunately, today I reviewed the right-left rule for another question and managed to construct the right thing… after seeing you say it's possible… before seeing that you gave the code :vP . -
David Rodríguez - dribeas over 13 yearsThe answer by chubsdad has the correct quote from the standard: you cannot return an array, but you can return a reference or pointer to an array. Arrays are non-copyable (as a type) and as such they cannot be returned --which would imply a copy-- and when that syntax is present the compiler will convert the argument into a pointer.
-
Potatoswatter over 13 years@David: So it does. This page is getting to be bizarrely long. Never have so many people voluntarily written so many trivial functions returning an array in one place.
-
cubuspl42 almost 10 yearsQuoting OP:
(...) you can consider the array returned arr2, totally another array (...)
-
MickyD almost 9 years
-
Amir about 8 years@seand remember the a[i] == *(a + sizeof(a)*i) rule
-
magras over 7 years@Amir, question has C++ tag, in which your expression evaluates to false.
-
Gabriel Staples over 6 years@BrentNash, your final example here begs the question, "why not just keep using
y
instead ofa
?" I think it would be helpful for you to add that when you modify an array inside of a function--the array having been passed into the function, the modifications are retained outside the function after it returns/exits, therefore,cout << y[0] << endl;
would print the exact same thing in this case ascout << a[0] << endl;
, again, because they
array was modified in place by the function. -
Gabriel Staples over 6 yearsI just edited the answer to include my comments. I hope that's ok. I think this is important info to make sure people understand.
-
Gabriel Staples over 6 yearsAlso, I would just use
void fillarr(int arr[])
if it was me writing this, instead ofint* fillarr(int arr[])
. Then, after I fill the array, if I really want a separate pointer variable, I'd useint* a = y
. This is simpler and more clear than having fillarr return something I think. -
Adrian over 6 yearsThis is not C++
-
hellow over 5 yearsPlease use proper english wording (you'll instead of u'll) and omit empty phrases like "buddy".
-
hellow over 5 yearsAlso: "then actually it is passed as a reference" is wrong. The variable
y
itself is passed as a copy of itself, but because it's a pointer, you will directly operate on the array. Please edit your answer. -
hellow over 5 yearsstackoverflow.com/questions/5573310/… TL;DR "Thus, the two forms are identical."
-
hellow over 5 yearsYes it is technically an array, you're right, but what is copied is a pointer to the array, not the array itself.
-
melpomene over 5 years@Amir There is no such rule.
a[i]
literally means*(a + i)
; your code is wrong. -
Amir over 5 years@melpomene yes i am developing c++ now i found that you are right. suggest me to remove my comment or not?
-
ajaysinghnegi over 5 years@magras I didn't get your comment
question has C++ tag, in which your expression evaluates to false
. How is it wrong incpp
? Kindly explain !! Also, what willsizeof(a)
return in*(a + sizeof(a)*i)
in @Amir comment? -
ajaysinghnegi over 5 years@Potatoswatter I am new to cpp, Can you explain the 2nd code snippet in detail? I am not able to break it into parts for the sake of understanding.
-
Potatoswatter over 5 years@AjaySinghNegi It’s the same as
typedef int arri5[5]; arri5 &fillarr( arri5 & arr ) { return arr; }
. Better to use typedef here. -
magras over 5 years@AjaySinghNegi,
sizeof(a)
will return size of pointer type, not the size of element. More than that in C++ pointer arithmetic already accommodates to pointed element size, so his rule could be corrected in two ways:a[i] == *(a + i)
or if you want to do it manually (and probably trigger UB)a[i] == *(int*)((char*)a + sizeof(*a) * i)
. Probably there is a difference between plain C and C++, which caused this confusion, but I don't know plain C. -
ajaysinghnegi over 5 years@magras Why does this gives the size of array, then? I mean, Shouldn't
sizeof(array)
give the total size of the array(sizeof(int) * total_no_of_elements
)? What is the difference b/w what you are saying and the one I've linked? -
magras over 5 years@AjaySinghNegi, there is a difference between array and pointer types. In this answer
a
declared as a pointer:int *a = fillarr(y);
. In C++ arrays doesn't store their size at run time. So information about size available only at compile time as a type. It isn't very easy to pass array types in and out of functions so, there are more modern ways to achieve the same goal. If you want to keep and work with array size at compile time, it's better to usestd::array
. Or if you want to have runtime sized array you can usestd::vector
specifying size at construct time. -
Potatoswatter about 5 years@ilw for example,
foo()[3] = 42;
. -
Potatoswatter about 5 years@ilw Just use
auto &&
. -
Potatoswatter about 5 years@ilw If you need to express something more specific, then it depends what. In any case, with a C++98 compiler, returning the pointer type is probably more portable, or defensive against compiler bugs.
-
Dan over 4 yearsLate to the discussion but I don't see it here and someone slap me if I'm missing it....what would be the advantage to returning an array or pointer to the array if the array memory location is being updated by the function to begin with? Or maybe there's not one?
-
Dan over 4 yearsagain, why return the type when the actual array is updated inside the function? Is it a matter of best practice?