is this allowed to pass an array by reference ?
void foo(double& *bar)
Seems that my compiler says no. Why? What is the proper way to pass an array by reference? Or a work around? I have an array argument that my method should modify and that I should retrieve afterwards. Alternatively, I could make this array a class member, which works fine, but it has many drawbacks for other part of my code (that I would like to avoid).
Thanks and regards.
Arrays can only be passed by reference, actually:
void foo(double (&bar)[10])
{
}
This prevents you from doing things like:
double arr[20];
foo(arr); // won't compile
To be able to pass an arbitrary size array to foo, make it a template and capture the size of the array at compile time:
template<typename T, size_t N>
void foo(T (&bar)[N])
{
// use N here
}
You should seriously consider using std::vector, or if you have a compiler that supports c++11, std::array.
Yes, but when argument matching for a reference, the implicit array to
pointer isn't automatic, so you need something like:
void foo( double (&array)[42] );
or
void foo( double (&array)[] );
Be aware, however, that when matching, double [42] and double [] are
distinct types. If you have an array of an unknown dimension, it will
match the second, but not the first, and if you have an array with 42
elements, it will match the first but not the second. (The latter is,
IMHO, very counter-intuitive.)
In the second case, you'll also have to pass the dimension, since
there's no way to recover it once you're inside the function.
As you are using C++, the obligatory suggestion that's still missing here, is to use std::vector<double>.
You can easily pass it by reference:
void foo(std::vector<double>& bar) {}
And if you have C++11 support, also have a look at std::array.
For reference:
http://de.cppreference.com/w/cpp/container/vector
http://de.cppreference.com/w/cpp/container/array
If you want to modify just the elements:
void foo(double *bar);
is enough.
If you want to modify the address to (e.g.: realloc), but it doesn't work for arrays:
void foo(double *&bar);
is the correct form.
8.3.5.8 If the type of a parameter includes a type of the form “pointer to array of unknown bound of T” or “reference
to array of unknown bound of T,” the program is ill-formed
Like the other answer says, put the & after the *.
This brings up an interesting point that can be confusing sometimes: types should be read from right to left. For example, this is (starting from the rightmost *) a pointer to a constant pointer to an int.
int * const *x;
What you wrote would therefore be a pointer to a reference, which is not possible.
Here, Erik explains every way pass an array by reference: https://stackoverflow.com/a/5724184/5090928.
Similarly, you can create an array reference variable like so:
int arr1[] = {1, 2, 3, 4, 5};
int(&arr2)[5] = arr1;
Related
is this allowed to pass an array by reference ?
void foo(double& *bar)
Seems that my compiler says no. Why? What is the proper way to pass an array by reference? Or a work around? I have an array argument that my method should modify and that I should retrieve afterwards. Alternatively, I could make this array a class member, which works fine, but it has many drawbacks for other part of my code (that I would like to avoid).
Thanks and regards.
Arrays can only be passed by reference, actually:
void foo(double (&bar)[10])
{
}
This prevents you from doing things like:
double arr[20];
foo(arr); // won't compile
To be able to pass an arbitrary size array to foo, make it a template and capture the size of the array at compile time:
template<typename T, size_t N>
void foo(T (&bar)[N])
{
// use N here
}
You should seriously consider using std::vector, or if you have a compiler that supports c++11, std::array.
Yes, but when argument matching for a reference, the implicit array to
pointer isn't automatic, so you need something like:
void foo( double (&array)[42] );
or
void foo( double (&array)[] );
Be aware, however, that when matching, double [42] and double [] are
distinct types. If you have an array of an unknown dimension, it will
match the second, but not the first, and if you have an array with 42
elements, it will match the first but not the second. (The latter is,
IMHO, very counter-intuitive.)
In the second case, you'll also have to pass the dimension, since
there's no way to recover it once you're inside the function.
As you are using C++, the obligatory suggestion that's still missing here, is to use std::vector<double>.
You can easily pass it by reference:
void foo(std::vector<double>& bar) {}
And if you have C++11 support, also have a look at std::array.
For reference:
http://de.cppreference.com/w/cpp/container/vector
http://de.cppreference.com/w/cpp/container/array
If you want to modify just the elements:
void foo(double *bar);
is enough.
If you want to modify the address to (e.g.: realloc), but it doesn't work for arrays:
void foo(double *&bar);
is the correct form.
8.3.5.8 If the type of a parameter includes a type of the form “pointer to array of unknown bound of T” or “reference
to array of unknown bound of T,” the program is ill-formed
Like the other answer says, put the & after the *.
This brings up an interesting point that can be confusing sometimes: types should be read from right to left. For example, this is (starting from the rightmost *) a pointer to a constant pointer to an int.
int * const *x;
What you wrote would therefore be a pointer to a reference, which is not possible.
Here, Erik explains every way pass an array by reference: https://stackoverflow.com/a/5724184/5090928.
Similarly, you can create an array reference variable like so:
int arr1[] = {1, 2, 3, 4, 5};
int(&arr2)[5] = arr1;
I know that when I want to pass an array to a function, it will decay into pointer, so its size won't be known and these two declarations are equivalent:
void funtion(int *tab, int size);
and
void funtion(int tab[], int size);
And I understand why. However, I checked that when I pass an array as a reference:
void funtion(int (&tab)[4]);
the compiler will know the size of the array and won't let me pass an array of different size as an argument of this function.
Why is that? I know that when I pass an array by address, the size isn't taken into account while computing the position of the ith element in the array, so it is discarded even if I explicitly include it in the function declaration:
void funtion(int tab[4], int size);
But what is different when I pass an array by reference? Why is its size known to the compiler?
Note: I'm interested in arrays whose size is known at compile time, so I didn't use any templates.
I found a similar question on Stack Overflow, however it doesn't answer my question - it doesn't explain why the compiler knows the size of the array, there is just some information on how to pass arrays to functions.
Because it can, and because checking adds extra safety. The compiler knows the size of the array because you tell it so, right there in the function declaration. And since that information is available, why wouldn't it use it to signal errors in your source code?
The real question is why your last example wouldn't do the same check. This is, unfortunately, another piece of C legacy - you are never passing an array, it always decays into a pointer. The size of the array then becomes irrelevant.
Could a check be added? Possibly, but it would be of limited use (since we are all using std::array now - right!?), and because it would undoubtedly break some code. This, for example:
void func (char Values [4]);
func ("x");
This is currently legal, but wouldn't be with an additional check on array size.
Because there is no odd implicit type change committed by the compiler in the case. Normally when you write:
void func(int[4]);
or
void func(void());
The compiler decides to "help" you and translates those into:
void func(int *);
or
void func(void(*)());
Funny thing though - it wouldn't aid you in such a way when you try returning one of those. Try writing:
int func()[4], func1()();
Ooops - surprise - compiler error.
Otherwise arrays are arrays and have constant size which can be acquired by using the sizeof operator.
This however is often forgotten because of the compiler behavior noted above and also because of the implicit pointer conversion applied to objects of array type when such isn't expected. And this is very often. Though here are the few exceptions when no implicit array object conversion is applied:
size_t arr[4],
(*parr)[3] = &arr, //taking the address of array
(&refarr)[3] = arr, //storing reference to array
sizearrobject = sizeof(arr); //taking the array object size
The above examples will trigger compiler error because of incompatible types on the second and third line.
I'm talking about the cases when arr object isn't automatically converted to something like this:
(size_t*)&arr
Well, there are several ways to pass an array to function. You can pass it by pointer an by reference, and there are ways to define or not to define it's size explicitely for both ways.
In your question you compare these 2 ways:
Pointer to first element: void f(int *arr)
Reference to an entire array: void f(int (&arr)[size])
You ask why you need to specify size only in one of these cases.
It looks like you assume that the only difference between them is the fact that one uses pointer and another uses reference. But this statement is incorrect, they have more differences: One is pointer to first element, but second is a reference to an entire array.
You can pass an array by pointer to an entire array:
void f(int (*arr)[size])
Compare it with your example, with passing by refence to an entire array:
void f(int (&arr)[size])
They are similar, they have similar syntax, they both explicitely define array size.
Also, consider this:
void f(int &arr)
It looks like passing a single int by reference, but you can pass an array of unknown size to it.
Pointer alternative to it is
void f(int *arr)
You ask why you need to specify array size only in one of those cases. It's because of the syntax you used, not because one is pointer and other is reference.
As I said, you can use pointer or reference. And you can specify array size or you can allow an array of any size to be used. These two are not connected.
// by pointer by reference
/* Any size */ void f(int *arr) void f(int &arr)
/* Specific size */ void f(int (*arr)[x]) void f(int (&arr)[x])
How can I pass a given std::vector<float> to a function to match the parameter type float (*parameter)[3]?
The function fills the parameter with coordinates of 3d points, that's the reason for the parameter type to be an array of 3-elements-long arrays. The function is provided by a library and I cannot change it.
I already initialized vector to cover enough elements.
void f(float (*parameter)[3])
{
}
int main()
{
vector<float> v(3);
f(reinterpret_cast<float(*)[3]>(&v[0]));
}
Because there is no way to ascertain that an std::allocator<T> involves in some configuration a float[3], it is not possible to point to such an array given an std::vector<T>. It is not a matter of finding the right cast, or the right value to cast.
The matter is that something like the function you described can only ever be passed a pointer to an actual float[3], or a null pointer.
The only strictly conformant thing you can do is to copy the data to and from a bona-fide float[3] variable, passing a pointer to it to your function.
How to find the size of string array passed to a function. The size should be computed inside the function.
#include<iostream>
using namespace std;
template <typename T,unsigned S>
unsigned arraysize(const T (&v)[S]) { return S; }
void func(string args[])
{
unsigned m=arraysize(args);
cout<<m;
}
int main()
{
string str_arr[]={"hello","foo","bar"};
func(str_arr);
}
What i dont understand is:
If the statement arraysize(str_arr) is used in main,it wouldn't pose a problem. The str_arr is an array, so str_arr acts as a pointer, so when we use arraysize(str_arr) that means we're sending the address to arraysize function.(correct me if i'm wrong).
But in function func(), i dont understand why there is a problem, i.e. the statement arraysize(args) sends the address of the string array args(or the address of pointer args).. or is it more complicated since it becomes some double pointer?? Explain?
Also please correct the above code..
str_arr is an array of strings. When you do sizeof(str_arr), you get the size of that array. However, despite the fact that args looks like an array of strings, it's not. An argument that looks like an array is really of pointer type. That is, string args[] is transformed to string* args by the compiler. When you do sizeof(args) you are simply getting the size of the pointer.
You can either pass the size of the array into the function or take a reference to the array with a template parameter size (as you did with arraysize):
template <size_t N>
void func(string (&args)[N])
{
// ...
}
There is no way to determine the size of an array when sent to a function. You also have to remember that only a pointer to the array is sent to the function, which makes it even theoretically quite implausible to calculate the array's size.
The information of the array's size is never visible in your function, as you threw it away when you decided to use string args[] for the argument. From the compiler's perspective, it's the same as string* args. You could change the function to:
template<size_t M>
void func(string (&args)[M])
{
cout<<M;
}
but it seems you already know that, right?
If the statement arraysize(str_arr) is used in main,it wouldn't pose a
problem. The str_arr is an array, so str_arr acts as a pointer, so
when we use arraysize(str_arr) that means we're sending the address to
arraysize function.(correct me if i'm wrong).
I have to correct you here. You state a correct premise, but draw the wrong conclusion.
The key point is indeed that str_arr is an array in main. While an array decays to a pointer in many (most) expression contexts, this does not apply when a reference to array is initialized. That is the reason why array_size is declared to take a reference to array parameter - this is the only way to have a parameter of array type, which implies that it comes with a defined length.
That is not the case for func. When a function parameter is declared to be of plain array type, the the array to pointer decay is applied to that declaraction. Your declaration of func is equivalent to void func(string * args). Thus args is a pointer, not an array. You could call func as
string str_non_array;
func(&str_non_array);
Because of this, a reference-to-array can't bind to it. And anyways, args has completely lost all information about the size of the array it is pointing to.
You could use the same reference-to-array trick as is used in arraysize: declare func as
template <std::size_t N>
void func(string (&args)[N]);
But this gets impractical to do everywhere (and may lead to code bloat, if applied naively to all array-handling code). The C++ equivalent of an array-with-length as available in other languages is std::vector<string> (for dynamically sized arrays) or std::array<string,N> (for fixed size known at compile time). Note that the latter can cause the same code bloat as mentioned above, so in most cases, std::vector<string> would be the preferred type for array that you need to pass to various functions.
Dmitry is right and I would like to explain it a bit further. The reason its happening is because array is not a First Class citizen in C++ and when passed as parameter it decays to pointer and what you get in called function is a pointer to its first element and size is lost.
You can refer C++ arrays as function arguments to see what alternative options are available.
I recently found some code like this:
typedef int TenInts[10];
void foo(TenInts &arr);
What can you do in the body of foo() that is useful, that you could not do if the declaration was:
void foo(int *arr); // or,
void foo(int arr[]); // or,
void foo(int arr[10]); // ?
I found a question that asks how to pass a reference to an array. I guess I am asking why.
Also, only one answer to "When is pointer to array useful?" discussed function parameters, so I don't think this is a duplicate question.
The reference-to-array parameter does not allow array type to decay to pointer type. i.e. the exact array type remains preserved inside the function. (For example, you can use the sizeof arr / sizeof *arr trick on the parameter and get the element count). The compiler will also perform type checking in order to make sure the array argument type is exactly the same as the array parameter type, i.e. if the parameter is declared as a array of 10 ints, the argument is required to be an array of exactly 10 ints and nothing else.
In fact, in situations when the array size is fixed at compile-time, using a reference-to-array (or pointer-to-array) parameter declarations can be preceived as the primary, preferred way to pass an array. The other variant (when the array type is allowed to decay to pointer type) are reserved for situations when it is necessary to pass arrays of run-time size.
For example, the correct way to pass an array of compile-time size to a function is
void foo(int (&arr)[10]); // reference to an array
or
void foo(int (*arr)[10]); // pointer to an array
An arguably incorrect way would be to use a "decayed" approach
void foo(int arr[]); // pointer to an element
// Bad practice!!!
The "decayed" approach should be normally reserved for arrays of run-time size and is normally accompanied by the actual size of the array in a separate parameter
void foo(int arr[], unsigned n); // pointer to an element
// Passing a run-time sized array
In other words, there's really no "why" question when it comes to reference-to-array (or pointer-to-array) passing. You are supposed to use this method naturally, by default, whenever you can, if the array size is fixed at compile-time. The "why" question should really arise when you use the "decayed" method of array passing. The "decayed" method is only supposed to be used as a specialized trick for passing arrays of run-time size.
The above is basically a direct consequence of a more generic principle. When you have a "heavy" object of type T, you normally pass it either by pointer T * or by reference T &. Arrays are no exception from this general principle. They have no reason to be.
Keep in mind though that in practice it is often makes sense to write functions that work with arrays of run-time size, especially when it comes to generic, library-level functions. Such functions are more versatile. That means that often there's a good reason to use the "decayed" approach in real life code, Nevertheless, this does not excuse the author of the code from recognizing the situations when the array size is known at compile time and using the reference-to-array method accordingly.
One difference is that it's (supposed to be) impossible to pass a null reference. So in theory the function does not need to check if the parameter is null, whereas an int *arr parameter could be passed null.
You can write a function template to find out the size of an array at compile time.
template<class E, size_t size>
size_t array_size(E(&)[size])
{
return size;
}
int main()
{
int test[] = {2, 3, 5, 7, 11, 13, 17, 19};
std::cout << array_size(test) << std::endl; // prints 8
}
No more sizeof(test) / sizeof(test[0]) for me ;-)
Shouldn't we also address the words in bold from the question:
What can you do in the body of foo() that is useful, that you could not do if the declaration was void foo(int arr[]);?
The answer is: nothing. Passing an argument by reference allows a function to change its value and pass back this change to the caller. However, it is not possible to change the value of the array as a whole, which would have been a reason to pass it by reference.
void foo(int (&arr)[3]) { // reference to an array
arr = {1, 2 ,3}; // ILLEGAL: array type int[3] is not assignable
arr = new(int[3]); // same issue
arr = arr2; // same issue, with arr2 global variable of type int[3]
}
You can ensure that the function is only called on int arrays of size 10. That may be useful from a type-checking standpoint.
You get more semantic meaning regarding what the function is expecting.