Array/pointer/reference confusion [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Confusion over C++ pointer and reference topic
Suppose I am passing
int arr[10];
as a parameter to a function.
Are all of these valid function prototypes? How do they differ in terms of arguments and why?
This is what I know so far (not sure if correct or not)
1. void foo(int &arr); //a reference to an array, which preserve the size attribute?
2. void foo(int &arr[]); //the same (is it)?
3. void foo(int (&arr)[]); //I don't know
4. void foo(int &arr[10]); //is it the same as 2?
5. void foo(int (&arr)[10]);//no idea
6. void foo(int *arr); //a decayed pointer of the array, pointing to the first element of the array, losing the size attribute?
7. void foo(int *arr[]); //the same (is it?)
8. void foo(int (*arr)[]); //a pointer to an array, preserve the size
9. void foo(int *arr[10]); //the same as 7 (is it?)
10. void foo(int (*arr)[10]);//is the same as 8 (is it?)
11. void foo(int arr[]); //is the same as 6 (is it?)
12. void foo(int arr[10]); // is the same as 6 (is it?)
(I know this will need a lengthy explanation, sorry, I'm totally confused...)

The first important piece of information is that parameters whose type is a (bounded or unbounded) array of T are transformed to pointers to T. I.e. both int arr[] and int arr[10] are transformed to int * arr. Note that the transformation is only performed on top-level arrays, i.e. it doesn't occur in int (*arr)[10], which is a pointer to an array of int.
Furthermore, things to the right of the identifier bind more closely than things to the left, i.e. int *arr[10] is an array, whereas int (*arr)[10] is a pointer.
Lastly, arrays of and pointers to references are invalid, as are pointers and references to unbounded arrays.
1. void foo(int &arr); // can't pass, reference to int
2. void foo(int &arr[]); // invalid, pointer to reference to int
3. void foo(int (&arr)[]); // invalid, reference to unbounded array of int
4. void foo(int &arr[10]); // invalid, pointer to reference to int
5. void foo(int (&arr)[10]); // can pass, reference to an array of int
6. void foo(int *arr); // can pass, pointer to int
7. void foo(int *arr[]); // can't pass, pointer to pointer to int
8. void foo(int (*arr)[]); // invalid, pointer to an unbounded array of int.
9. void foo(int *arr[10]); // can't pass, pointer to pointer to int
10. void foo(int (*arr)[10]); // can't pass, pointer to array of int
11. void foo(int arr[]); // can pass, pointer to int
12. void foo(int arr[10]); // can pass, same as above
Using arr as an argument to foo will cause it to decay to a pointer to its first element -- the value passed to foo will be of type int *. Note that you can pass &arr to number 10, in which case a value of type int (*)[10] would be passed and no decay would occur.

The difficult part is to consider that array don't pass by value, but decay into pointers.
Some of your declaration are syntax errors, some other are not (but are also not what you probably think)
In your case, teh only one that make sense are 6, 11 and 12.
2, 3 ,4 and 8 have self explanatory error messages. (if you don't understand them is most likely because you read the declaration with a wrong operator priority)
t1.cpp:2:19: error: declaration of 'arr' as array of references
t1.cpp:3:22: error: parameter 'arr' includes reference to array of unknown bound 'int []'
t1.cpp:4:21: error: declaration of 'arr' as array of references
t1.cpp:8:22: error: parameter 'arr' includes pointer to array of unknown bound 'int []'
The others are somehow redundant (reference-to-array or -pointer-, they will behave the same inside the function) or simply wrong because declaring something different as you intend (like 7,9,10: they represent a "double indirection", while a plain array has a single one, and 1. that doesn't represent any indirection: it just aliases a single int)

Related

Why is that you can modify an array inside a function without using any reference or pointer [duplicate]

This question already has answers here:
Array changed in a void function, is still changed outside! why? (scope)
(4 answers)
Passing an array as a parameter in C
(3 answers)
Passing Arrays to Function in C++
(5 answers)
Passing an array as an argument to a function in C
(11 answers)
Closed 11 months ago.
I don't get it why you can alter the values inside the array, without using a reference or a pointer (&, *), I'm a freshmen student, and I don't know the reason behind, I hope someone can provide a logical answer, please refer to the code below, Thank You in Advance.
#include <iostream>
using namespace std;
void a(int x[]){
for(int i = 0; i < 5; i++){
x[i] += 2;
}
}
int main(){
int x[5] = {1,2,3,4,5};
a(x);
for(auto b : x){
cout << b << " ";
}
return 0;
}
A function parameter is never an array in C++. When you declare a function parameter as an array, it is automatically adjusted to be a pointer to element of such array. These declarations are effectively identical:
void a(int x[]); // looks like an array of int of unknown bound
void a(int* x); // declaration above is adjusted to this
void a(int x[1234]); // the size is ignored completely
An array implicitly converts to a pointer to the first element of the array (such conversion is called decay). Hence, you can call the function that doesn't accept an array parameter by passing an array argument:
int* ptr1 = x; // implicit conversion
int* ptr2 = &x[0]; // same conversion explicitly
a(x); // same conversion happens here
These two rules (function parameter adjustment and array to pointer decay) make it so that what syntactically looks like passing arrays by value, is actually done using indirection. Within the function, you modify the elements by indirecting through the pointer parameter that points to the array that exists outside of the function.
Important note: The adjustment of array to pointer in function parameter does not apply in other contexts. Arrays and pointers are distinct types with different properties.
Another note: The adjustment does not apply to parts of compound types. For example, a function parameter of type "pointer to array" will not be adjusted to be "pointer to pointer" and "reference to array" will not be adjusted to be "reference to pointer".
The parameter having the array type in this function declaration
void a(int x[]){
is adjusted by the compiler to pointer type to array elements type. That is the above declaration is equivalent to
void a(int *x){
In this call of the function
a(x);
the array designator is implicitly converted to pointer to its first element. That is the call is equivalent to
a( &x[0]);
So within the function you have a pointer to the first element of the array declared in main.
Using the pointer arithmetic you can access elements of the array. That is the elements of the array are passed to the function by reference in the C meaning indirectly through a pointer to them.
Within the function the variable x has the type int *. And this expression statement
x[i] += 2;
is equivalent to
*( x + i ) += 2;
Beacuse
void a(int x[]){
is the same as
void a(int *x){
and so you are using a pointer
Why?
Because an array like
int x[10];
'decays' to a pointer when passed to a function (and in other places). This can be very confusing but at the same time is very flexible
It mens that I can have a function like strlen that can accpet a 'real' array, or a pointer. These 'strings'
char *s1 = malloc(10);
strcpy(s1, "hello");
char s2[] = "hello";
char *s3 = "hello";
store their data in different ways but all can be handled by
size_t strlen(const char *s);
note that this is exactly the same as
size_t strlen(const char s[]);
they are 2 different ways of writing the same thing. Personal preference is for the second type if its really is an 'array' vs a pointer to maybe an array.
One issue with this 'decay' is that inside strlen (or any pointer/array accepting function) it is impossible to 'know' the length just from the parameter. The compiler knows that the size of s2 is 6 but this information is not carried forward to the function.
Regularly SO sees this
void my_func(int *arr){
int len = sizeof(arr)/sizeof(arr[0]);
....
}
int a[10];
my_func(a);
This will give len = 1 or 2 (depending on 32 or 64 bit machine), never 10
The flexibility costs a litle power

How do I pass an array as an reference to a pointer of const char? [duplicate]

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.

Template function array loop [duplicate]

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.

C++ passing array using reference operator

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.

very basic c question

as we use pointers in the argument list of functions like
void f(int *);
this means that this function will receive a pointer to an integer
but what does this means
void f(int ***);
and
void f(int **=0)
void f(int ***);
means that the function receives a pointer to a pointer to a pointer to an int. This would work with it:
int x=42;
int *px=&x;
int **ppx=&px;
int ***pppx=&ppx;
f(pppx);
Now about the 2nd one, its a function that receives a pointer to a pointer to an int, and if you give it nothing, it defaults to 0.
int x=42;
int *px=&x;
int **ppx=&px;
f(ppx); // pt to pt to x
f(); // same as f(0)
UPDATE:
A practical application of this kind of double pointers is a memory allocation routine like:
bool alloc(T **mem, int count);
This function returns true/false depending on whether or not it worked and would update the pointer you pass in with the real memory address, like this:
T *mem;
verify(alloc(&mem, 100));
You pass in an uninitialized pointer and the function can overwrite it with a real value because you passed a pointer to the actual pointer. At the end, mem contains a pointer to valid memory.
Another application, more common but a lot less enlightening, is an array of arrays (so-called jagged arrays).
int ***
is a pointer to a pointer to a pointer to an int. Think of it as (((int*)*)*).
void f(int **=0)
This function takes a pointer to an int pointer as an argument, but can also be called without arguments in which case the argument will be 0.
void f(int ***);
Here f takes a pointer to pointer to pointer to an int.
void f(int **=0)
This function takes a pointer to pointer to an int as an argument, but this arguments is optional and has a default value of 0 (i.e null)
void f(int ***);
here the function argument is a pointer to a pointer to a pointer to an int (or more likely to many of them).
void f(int **=0)
and here it's just a pointer to a pointer to an int that gets initialized to be 0 (the pointer to the ... is 0, not the int) if the argument is not specified when the function is invoked (optional parameter).
What you are asking about is Multiple Indirection. That page sums up the problem very well, I highly recommend reading that entire page on pointers, it is golden.
void f(int ***);
As the other answers explain, this is a pointer to a pointer to a pointer to an int. It suggest to me that the programmer was not a very good programmer - he (and it was almost certainly a he) was too busy showing off how clever he was with 3 levels of indirection to consider the difficulty of maintaining overly obscure code like this. I've never had to use 3 levels of indirection in approx 20 years of programming in C and C++, and rarely use 2.