How does passing a statically allocated array by reference work?
void foo(int (&myArray)[100])
{
}
int main()
{
int a[100];
foo(a);
}
Does (&myArray)[100] have any meaning or its just a syntax to pass any array by reference?
I don't understand separate parenthesis followed by big brackets here. Thanks.
It's a syntax for array references - you need to use (&array) to clarify to the compiler that you want a reference to an array, rather than the (invalid) array of references int & array[100];.
EDIT: Some clarification.
void foo(int * x);
void foo(int x[100]);
void foo(int x[]);
These three are different ways of declaring the same function. They're all treated as taking an int * parameter, you can pass any size array to them.
void foo(int (&x)[100]);
This only accepts arrays of 100 integers. You can safely use sizeof on x
void foo(int & x[100]); // error
This is parsed as an "array of references" - which isn't legal.
It's just the required syntax:
void Func(int (&myArray)[100])
^ Pass array of 100 int by reference the parameters name is myArray;
void Func(int* myArray)
^ Pass an array. Array decays to a pointer. Thus you lose size information.
void Func(int (*myFunc)(double))
^ Pass a function pointer. The function returns an int and takes a double. The parameter name is myFunc.
It is a syntax. In the function arguments int (&myArray)[100] parenthesis that enclose the &myArray are necessary. if you don't use them, you will be passing an array of references and that is because the subscript operator [] has higher precedence over the & operator.
E.g. int &myArray[100] // array of references
So, by using type construction () you tell the compiler that you want a reference to an array of 100 integers.
E.g int (&myArray)[100] // reference of an array of 100 ints
The following creates a generic function, taking an array of any size and of any type by reference:
template<typename T, std::size_t S>
void my_func(T (&arr)[S]) {
// do stuff
}
play with the code.
Arrays are default passed by pointers. You can try modifying an array inside a function call for better understanding.
Related
How does passing a statically allocated array by reference work?
void foo(int (&myArray)[100])
{
}
int main()
{
int a[100];
foo(a);
}
Does (&myArray)[100] have any meaning or its just a syntax to pass any array by reference?
I don't understand separate parenthesis followed by big brackets here. Thanks.
It's a syntax for array references - you need to use (&array) to clarify to the compiler that you want a reference to an array, rather than the (invalid) array of references int & array[100];.
EDIT: Some clarification.
void foo(int * x);
void foo(int x[100]);
void foo(int x[]);
These three are different ways of declaring the same function. They're all treated as taking an int * parameter, you can pass any size array to them.
void foo(int (&x)[100]);
This only accepts arrays of 100 integers. You can safely use sizeof on x
void foo(int & x[100]); // error
This is parsed as an "array of references" - which isn't legal.
It's just the required syntax:
void Func(int (&myArray)[100])
^ Pass array of 100 int by reference the parameters name is myArray;
void Func(int* myArray)
^ Pass an array. Array decays to a pointer. Thus you lose size information.
void Func(int (*myFunc)(double))
^ Pass a function pointer. The function returns an int and takes a double. The parameter name is myFunc.
It is a syntax. In the function arguments int (&myArray)[100] parenthesis that enclose the &myArray are necessary. if you don't use them, you will be passing an array of references and that is because the subscript operator [] has higher precedence over the & operator.
E.g. int &myArray[100] // array of references
So, by using type construction () you tell the compiler that you want a reference to an array of 100 integers.
E.g int (&myArray)[100] // reference of an array of 100 ints
The following creates a generic function, taking an array of any size and of any type by reference:
template<typename T, std::size_t S>
void my_func(T (&arr)[S]) {
// do stuff
}
play with the code.
Arrays are default passed by pointers. You can try modifying an array inside a function call for better understanding.
I'm still new to C++ and I've got a question concerning arrays as parameters in functions/ constructors. I've realized that it is possible to declare an array in two ways (maybe there are more, which I haven't seen before):
1.
void foo(int arr[]);
2.
void foo(int arr);
In both cases, arr can be used in the following way:
arr[0] = 1;
But what is the difference between those? Or is it just a matter of clarity?
The difference is one is a variable, the other an array.
void my_func(int array[]); // Function with array parameter.
void your_func(int variable); // Function with variable parameter.
The notation:
int v;
v[5] = 6;
should generate a compilation error or warning because the v variable is not an array nor a pointer.
I have a question about passing array with reference operator. I want to write code that pass array using reference operator. Then I tried
void swap(int &testarray[3]){
// code
}
It gives me error. It says,
/main.cpp:5: error: declaration of 'testarray' as array of references
However when changed my code with
void swap(int (&testarray)[3]){
// code
}
It runs properly. Only difference is having bracket.
Why it needs bracket and what is the difference between int (&testarray)[3] and int &testarray[3]
Thanks for helping.
void foo(int &testarray[3]) is interpreted as void foo((int &)testarray[3]) due to priority. And array of references are illegal.
Whereas void foo(int (&testarray)[3]) is interpreted as you want. (reference of an array of 3 int).
void foo(int testarray[3]) is equivalent to void foo(int testarray[])
which decays to void foo(int *testarray). (int pointer).
In fact this construction
int & testarray[3]
defines an array of references to integral objects. The C++ Standard does not allow to define arrays of references to objects.
My question is: when i write a function prototype in C like this:
void foo(int *vector);
It's the same thing to do:
void foo(int vector[MAX_LENGTH]);
To the function, is passed always as a pointer? The code it's the same?
Thanks in advance.
This is subtle. Arrays in C are not pointers, but C does not allow arrays to be passed as function parameters. So when you have void foo(int vector[MAX_LENGTH]);, essentially all you're doing is telling other programmers (and your future self) that this function expects an array of MAX_LENGTH to be passed to it. The compiler won't help you. It will silently cast your array to a pointer.
This explains it pretty well.
Yes an array type is implicitly converted to a pointer type when passed to a function.
So
void foo(int *a) and void foo(int a[]) are identical.
You can easily check that using sizeof() operator inside the function definition
For example
void foo(int a[])
{
std::cout<<sizeof(a); //prints sizeof(int*)
}
int main()
{
int a[]={1,2,3,4};
foo(a);
}
EXTRA (Printing size of an array inside a function)
[C++ Only]
template<typename T,size_t n>
void size_of_array(T (&a)[n]) //Array passed by reference. Template argument deduction
{
std::cout<<sizeof(a); //prints sizeof(n*sizeof(int))
}
int main()
{
int a[]={1,2,3,4,5};
size_of_array(a);
}
This is one of the rough edges of the C language(s). Two declaration that look exactly the same (but for the names), one in the prototype and one as a stack variable, result in the declaration of two different types of variables.
void foo(int A[10]) {
int B[10];
}
Inside the scope of foo, A is pointer to int and B is array of ten elements of type int. As somebody else mentioned, even their sizes computed with sizeof are different.
C++ inherited the rule, so for your example code the prototypes of both functions should be the same.
C99 complicates this matter even further by introducing the new keyword static ;-)
void foo(int A[static 10]) {
int B[10];
}
this doesn't change the rules on how A and B are seen from the inside, but provides an information to the caller side of howmuch array elements are expected. For the moment gcc accepts this new syntax and simply ignores this information.
there's little else it could pass! the [] contraint lets the compiler do more checks though.
Ref. to my last post and sellibitze's comment to that post on passing array by ref rather than by value, why is it that when I'm passing array by value compiler can deduce arguments but it won't do it if I pass it by value?
template<class T,int row, int col>
void invert(T (&a)[row][col]) //NOTE AMPERSAND
in main with declaration above I can call:
int main(int argc, char* argv[])
{
invert(a);//HERE ARGUMETS ARE AUTOMATICALLY DEDUCED
}
but without ampersand I would have to call it like so:
int main(int argc, char* argv[])
{
invert<int,3,4>(a);
}
#Paul So just to make it clear when I'm declaring fnc:
void f(int a[]);//I'm passing a pointer
but when I'm declaring:
void f(int &a[]);//I'm passing a ref?
Do I understand this correctly now?
That's because when you pass an array "by value" it decays to a pointer. That is, you are in fact passing a pointer to the first element without any size information.
When you have a signature like this:
void foo(int arr[10]);
then the value 10 is completely ignored and you can pass arrays of ints of any size to it. It is exactly the same as
void foo(int arr[]);
or
void foo(int* arr);
As you can see the size information is not preserved, and therefore it cannot be used to deduce the size of the array.
With a two-dimensional array, the first dimension decays. For example: an array of 10 arrays of 20 integers (int arr[10][20]) decays to a pointer to arrays of 20 integers (int (*arr)[20]) etc, so the value 10 cannot be deduced but the size of the second dimension (20) is preserved an can be deduced.
template<class T,int row, int col>
void foo(T (&a)[row][col]) { }
template <class T, int col>
void bar(T arr[][col]) {}
int main()
{
int a[10][20];
foo(a);
bar(a);
}
When you pass something by reference, the type is preserved, the arrays don't decay and all the size information will remain available.
You can't pass array by value, only by pointer (when you pass an array to a function it's automatically converted to a pointer).
I don't really understand what you mean by "deduce arguments"; do you mean the total size of the array? If yes then if you pass it by pointer it's lost because pointers don't carry that kind of information.
Anyways I highly recommend to use std::vector rather than plain old C arrays; many less headaches! They are passed by value by default (as you would expect); they can easily passed by reference and by pointer if you want to, and they never lose information such as the array size. They also protected against buffer overflows and underflows, and they automatically grow as you add more elements.
void f(int &a[]); // I'm passing a ref?
No, here you try to pass an array of references, which does not exist in the type system. You might be tempted to write the following:
void f(int (&a)[]);
But references to arrays of unknown bound are not allowed as function parameters.
When you declare a function parameter as an array of n dimensions, it is rewritten by the compiler as a pointer to an array of n-1 dimensions. The following signatures are equivalent:
void fun(int x[][10]);
void fun(int x[2][10]);
void fun(int x[99][10]);
void fun(int (*x)[10]);
The bound of the first dimension is ignored and thus cannot be inferred by the template mechanism.
What you can do is pass a pointer to the entire 2D array:
template <class T, int row, int col>
void invert(T (*a)[row][col])
{
std::cout << row << " x " << col << std::endl;
T first_entry = (*a)[0][0];
}
int main(int argc, char* argv[])
{
int a[10][20];
invert(&a);
}
This works as expected, but as you can see, the syntax is a little clumsy on both sides.