#include<stdio.h>
int main(){
int a[] = {1,2,3};
int b[] = {4,5,6};
b = a;
return 0;
}
Result in this error:
array type 'int [3]' is not assignable
I know arrays are lvalues and are not assignable but in this case, all the compiler has to do is
reassign a pointer. b should just point to the address of a. Why isn't this doable?
"I know arrays are lvalues and are not assignable but in this case, all the compiler has to do is reassign a pointer."
"b should just point to the address of a. Why isn't this doable?"
You seem to confuse here something. b isn't a pointer. It is an array of three int elements.
b = a;
Since b is used here as lvalue in the assignment, it is taken as of type int [3], not int *. The pointer to decay rule takes no place in here for b, only for a as rvalue.
You cannot assign an array (here b) by a pointer to the first element of another array (here a) by using b = a; in C.
The syntax doesn't allow that.
That's what the error
"array type 'int [3]' is not assignable"
is saying to you for b.
Also you seem to be under the misunderstanding that the pointer to decay rule means that an array is anyhow converted to a pointer object, which can in any manner store addresses of locations of different objects.
This is not true. This conversion is only happening in a very implicit kind of way and is subject of this SO question:
Is the array to pointer decay changed to a pointer object?
If you want to assign the values from array a to the array b, you can use memcpy():
memcpy(b, a, sizeof(a));
I know arrays are lvalues and are not assignable but in this case, all the compiler has to do is reassign a pointer. b should just point to the address of a. Why isn't this doable?
Because b isn't a pointer. When you declare and allocate a and b, this is what you get:
+---+
| 1 | a[0]
+---+
| 2 | a[1]
+---+
| 3 | a[2]
+---+
...
+---+
| 4 | b[0]
+---+
| 5 | b[1]
+---+
| 6 | b[2]
+---+
No space is set aside for any pointers. There is no pointer object a or b separate from the array elements themselves.
C was derived from an earlier language called B, and in B there was a separate pointer to the first element:
+---+
b: | +-+--+
+---+ |
... |
+----+
|
V
+---+
| | b[0]
+---+
| | b[1]
+---+
...
+---+
| | b[N-1]
+---+
When Dennis Ritchie was developing C, he wanted to keep B's array semantics (specifically, a[i] == *(a + i)), but he didn't want to store that separate pointer anywhere. So instead he created the following rule - unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array, and that value is not an lvalue.
This has several practical effects, the most relevant here being that an array expression may not be the target of an assignment. Array expressions lose their "array-ness" under most circumstances, and simply are not treated like other types.
Edit
Actually, that misstates the case - array expression may not be the target of an assignment because an array expression is not a modifiable lvalue. The decay rule doesn't come into play. But the statement "arrays are not treated like other types" still holds.
End Edit
The upshot is that you cannot copy the contents of one array to the other using just the = operator. You must either use a library function like memcpy or copy each element individually.
Others already explained what you got wrong. I'm writing that answer to explain that actually the compiler could assign an array to another, and you can achieve the same effect with minimal change to your sample code.
Just wrap your array in a structure.
#include <stdio.h>
int main(){
struct Array3 {
int t[3];
};
struct Array3 a = {{1,2,3}};
struct Array3 b = {{4,5,6}};
a = b;
printf("%d %d %d", a.t[0], a.t[1], a.t[2]);
return 0;
}
Once the array is wrapped in a structure copying the array member of the structure works exactly as copying any other member. In other words you are copying an array. This trick is usefull in some cases like when you really want to pass an array to a function by copying it. It's slightly cleaner and safer than using memcopy for that purpose, which obviously would also work.
Henceforth the reason why it is not allowed for top level arrays is not because the compiler can't do it, but merely because that's not what most programmers usually wants to do.
Usually they just want to decay the array to a pointer. Obviously that is what you thought it should do, and direct copy of array is likely forbiden to avoid specifically that misunderstanding.
From The C Programming Language:
The array name is the address of the zeroth element.
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable. But an array name is not a variable.
My understanding is that the array name is a constant, so it can't be assigned.
The variable b in your code is allocated on the stack as 3 consecutive ints. You can take the address of b and store it in a variable of type int*.
You could assign a value to it if you allocate the array on the heap and store only the pointer to it on the stack, in this case you could, in fact, be able to change the value of the pointer to be the same as a.
Related
This program works in C:
#include <stdio.h>
int main(void) {
char a[10] = "Hello";
char *b = a;
printf("%s",b);
}
There are two things I would expect to be different. One is that we in the second line in the main write: "char *b = &a", then the program is like this:
#include <stdio.h>
int main(void) {
char a[10] = "Hello";
char *b = &a;
printf("%s",b);
}
But this does not work. Why is that? Isn't this the correct way to initialize a pointer with an adress?
The second problem I have is in the last line we should have: printf("%s",*b) so the program is like this:
#include <stdio.h>
int main(void) {
char a[10] = "Hello";
char *b = a;
printf("%s",*b);
}
But this gives a segmentation fault. Why does this not work? Aren't we supposed to write "*" in front of a pointer to get its value?
There is a special rule in C. When you write
char *b = a;
you get the same effect as if you had written
char *b = &a[0];
That is, you automatically get a pointer to the array's first element. This happens any time you try to take the "value" of an array.
Aren't we supposed to write "*" in front of a pointer to get its value?
Yes, and if you wanted to get the single character pointed to by b, you would therefore need the *. This code
printf("first char: %c\n", *b);
would print the first character of the string. But when you write
printf("whole string: %s\n", b);
you get the whole string. %s prints multiple characters, and it expects a pointer. Down inside printf, when you use %s, it loops over and prints all the characters in the string.
Expanding on Steve's answer (which is the correct one to accept)...
This is the special rule he's talking about:
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. If the array object has
register storage class, the behavior is undefined.
C 2011 Prepublication Draft
Arrays are weird and don't behave like other types. You don't get this "decay to a pointer to the first element" behavior in other aggregate types like struct types. You can't assign the contents of an entire array with the = operator like you can with struct types; for example, you can't do something like
int a[5] = {1, 2, 3, 4, 5};
int b[5];
...
b = a; // not allowed; that's what "is not an lvalue" means
Why are arrays weird?
C was derived from an earlier language named B, and when you declared an array in B:
auto arr[5];
the compiler set aside an extra word to point to the first element of the array:
+---+
arr: | | ----------+
+---+ |
... |
+---+ |
| | arr[0] <--+
+---+
| | arr[1]
+---+
| | arr[2]
+---+
| | arr[3]
+---+
| | arr[4]
+---+
The array subscript operation arr[i] was defined as *(arr + i) - given the starting address stored in arr, offset i elements from that address and dereference the result. This also meant that &arr would yield a different value from &arr[0].
When he was designing C, Ritchie wanted to keep B's array subscripting behavior, but he didn't want to set aside storage for the separate pointer that behavior required. So instead of storing a separate pointer, he created the "decay" rule. When you declare an array in C:
int arr[5];
the only storage set aside is for the array elements themselves:
+---+
arr: | | arr[0]
+---+
| | arr[1]
+---+
| | arr[2]
+---+
| | arr[3]
+---+
| | arr[4]
+---+
The subscript operation arr[i] is still defined as *(arr + i), but instead of storing a pointer value in arr, a pointer value is computed from the expression arr. This means &arr and &arr[0] will yield the same address value, but the types of the expressions will be different (int (*)[5] vs int *, respectively).
One practical effect of this rule is that you can use the [] operator on pointer expressions as well as array expressions - given your code you can write b[i] and it will behave exactly like a[i].
Another practical effect is that when you pass an array expression as an argument to a function, what the function actually receives is a pointer to the first element. This is why you often have to pass the array size as a separate parameter, because a pointer only points to a single object of the specified type; there's no way to know from the pointer value itself whether you're pointing to the first element of an array, how many elements are in the array, etc.
Arrays carry no metadata around, so there's no way to query an array for its size, or type, or anything else at runtime. The sizeof operator is computed at compile time, not runtime.
I know array in C does essentially behaves like a pointer except at some places like (sizeof()). Apart from that pointer and array variables dont differ except in their declaration.
For example consider the two declarations:
int arr[] = {11,22,33};
int *arrptr = arr;
Now here is how they behave same:
printf("%d %d", arrptr[0], arr[0]); //11 11
printf("%d %d", *arrptr, *arr); //11 11
But here is one more place I found they differ:
//the outputs will be different on your machine
printf("%d %d", &arrptr, &arr); //2686688 2686692 (obviously different address)
printf("%d %d", arrptr, arr); //2686692 2686692 (both same)
Here the issue is with last line. I understand that arrptr contains the address of arr. Thats why the first address printed in last line is 2686692. I also understand that logically the address (&arr) and contents (arr) of arr should be same unlike arrptr. But then whats exactly that which (internally at implementation level) that makes this happen?
When the unary & operator is applied to an array, it returns a pointer to an array. When applied to a pointer, it returns a pointer to a pointer. This operator together with sizeof represent the few contexts where arrays do not decay to pointers.
In other words, &arrptr is of type int **, whereas &arr is of type int (*)[3]. &arrptr is the address of the pointer itself and &arr is the beginning of the array (like arrptr).
The subtle part: arrptr and &arr have the same value (both point to the beginning of the array), but are of a different type. This difference will show if you do any pointer arithmetic to them – with arrptr the implied offset will be sizeof(int), whereas with &arr it will be sizeof(int) * 3.
Also, you should be using the %p format specifier to print pointers, after casting to void *.
I know array in C does essentially behaves like a pointer except at some places like (sizeof()). Apart from that pointer and array variables dont differ except in their declaration.
This is not quite true. Array expressions are treated as pointer expressions in most circumstances, but arrays and pointers are completely different animals.
When you declare an array as
T a[N];
it's laid out in memory as
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[N-1]
+---+
One thing immediately becomes obvious - the address of the first element of the array is the same as the address of the array itself. Thus, &a[0] and &a will yield the same address value, although the types of the two expressions are different (T * vs. T (*)[N]), and the value may possibly adjusted based on type.
Here's where things get a little confusing - except when it is the operand of the sizeof or unary & operator, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
This means the expression a also yields the same address value as &a[0] and &a, and it has the same type as &a[0]. Putting this all together:
Expression Type Decays to Value
---------- ---- --------- -----
a T [N] T * Address of a[0]
&a T (*)[N] n/a Address of a
*a T n/a Value of a[0]
a[i] T n/a Value of a[i]
&a[i] T * n/a Address of a[i]
sizeof a size_t n/a Number of bytes in a
So why does this conversion rule exist in the first place?
C was derived from an earlier language called B (go figure). B was a typeless
language - everything was treated as basically an unsigned integer. Memory
was seen as a linear array of fixed-length "cells". When you declared an
array in B, an extra cell was set aside to store the offset to the first
element of the array:
+---+
a:| | ----+
+---+ |
... |
+-------+
|
V
+---+
| | a[0]
+---+
| | a[1]
+---+
...
+---+
| | a[N-1]
+---+
The array subscript operation a[i] was defined as *(a + i); that is, take the offset value stored in a, add i, and dereference the result.
When Ritchie was designing C, he wanted to keep B's array semantics, but couldn't figure out what to do with the explicit pointer to the first element, so he got rid of it. Thus, C keeps the array subscripting definition a[i] == *(a + i) (given the address a, offset i elements from that address and dereference the result), but doesn't set aside space for a separate pointer to the first element of the array - instead, it converts the array expression a to a pointer value.
This is why you see the same output when you print the values of arr and arrptr. Note that you should print out pointer values using the %p conversion specifier and cast the argument to void *:
printf( "arr = %p, arrptr = %p\n", (void *) arr, (void *) arrptr );
This is pretty much the only place you need to explicitly cast a pointer value to void * in C.
int array[] = {1,2,3,4};
As I understand, array is just a pointer to &array[0]
But how come then sizeof(array); knows size of an array and not just that it's only 4 byte number?
Although the name of the array does become a pointer to its initial member in certain contexts (such as passing the array to a function) the name of the array refers to that array as a whole, not only to the pointer to the initial member.
This manifests itself in taking the size of the array through sizeof operator.
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T, and the value of the expression will be the address of the first element of the array.
Arrays in C don't store any metadata about their size or anything else, nor is any storage set aside for any sort of pointer. They're laid out pretty much as follows:
+---+
arr: | 1 | arr[0]
+---+
| 2 | arr[1]
+---+
| 3 | arr[2]
+---+
| 4 | arr[3]
+---+
There's no separate storage for a variable arr apart from the array elements themselves. As you can see, the address of arr and the address of arr[0] are the same. This is why the expressions arr, &arr, and &arr[0] all give you the same value (the address of the first element), even though the types of those expressions are different.
Except when the operand is a variable-length array, the result of sizeof is computed at compile time, and the compiler treats array operands as arrays in those circumstances; otherwise, it treats the array expression as a pointer to the first element.
No, array is not just a pointer, as your sizeof example shows.
It is only that in most contexts, it is converted to &array[0], but not in all.
This does only work within the scope where you define the array. If you pass your array to a function the sizeof operator doesn't work anymore.
I'm not completely sure but I think that the compiler stores the length of the array and puts it back where you have sizeOf(array) like a macro but not dynamically. Please correct me if someone knows better.
In this declaration -
int a[] = {1,2,3,4}; // a is of array type
a becomes a pointer to first element of array a ( after decay ). Not in all cases both will be equal , but in cases such as when array is passed to function .
In C, you can declare an char array either by
char []array;
or
char *array;
The later one is a pointer, why can it be an array?
Pointers and arrays are two completely different animals; a pointer cannot be an array and an array cannot be a pointer.
The confusion comes from two concepts that aren't explained very well in most introductory C texts.
The first is that the array subscript operator [] can be applied to both pointer and array expressions. The expression a[i] is defined as *(a + i); you offset i elements from the address stored in a and dereference the result.
So if you declare a pointer
T *p;
and assign it to point to some memory, like so
p = malloc( N * sizeof *p );
you'll get something like the following:
+---+
p: | | ---+
+---+ |
... |
+---+ |
p[0]: | |<---+
+---+
p[1]: | |
+---+
...
+---+
p[N-1]: | |
+---+
p stores the base address of the array, so *(p + i) gives you the value stored in the i'th element (not byte) following that address.
However, when you declare an array, such as
T a[N];
what you get in memory is the following:
+---+
a[0]: | |
+---+
a[1]: | |
+---+
...
+---+
a[N-1]: | |
+---+
Storage has only been set aside for the array elements themselves; there's no separate storage set aside for a variable named a to store the base address of the array. So how can the *(a+i) mechanism possibly work?
This brings us to the second concept: except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array ijn a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
In other words, when the compiler sees the expression a in the code, it will replace that expression with a pointer to the first element of a, unless a is the operand of sizeof or unary &. So a evaluates to the address of the first element of the array, meaning *(a + i) will work as expected.
Thus, the subscript operator works exactly the same way for both pointer and array expressions. However, this does not mean that pointer objects are the same thing as array objects; they are not, and anyone who claims otherwise is confused.
I have the following C program:
#include <stdio.h>
int main(){
int a[2][2] = {1, 2, 3, 4};
printf("a:%p, &a:%p, *a:%p \n", a, &a, *a);
printf("a[0]:%p, &a[0]:%p \n", a[0], &a[0]);
printf("&a[0][0]:%p \n", &a[0][0]);
return 0;
}
It gives the following output:
a:0028FEAC, &a:0028FEAC, *a:0028FEAC
a[0]:0028FEAC, &a[0]:0028FEAC
&a[0][0]:0028FEAC
I am not able to understand why are &a, a, *a - all identical. The same for a[0], &a[0] and &a[0][0].
EDIT:
Thanks to the answers, I've understood the reason why these values are coming out to be equal. This line from the book by Kernighan & Ritchie turned out to be the key to my question:
the name of an array is a synonym for the location of the initial element.
So, by this, we get
a = &a[0], and
a[0] = &a[0][0] (considering a as an array of arrays)
Intuitively, now the reason is clear behind the output. But, considering how pointers are implemented in C, I can't understand how a and &a are equal. I am assuming that there is a variable a in memory which points to the array(and the starting address of this array-memory-block would be the value of this variable a).
But, when we do &a, doesn't that mean taking the address of the memory location where the variable a was stored? Why are these values equal then?
They're not identical pointers. They're pointers of distinct types that all point to the same memory location. Same value (sort of), different types.
A 2-dimensional array in C is nothing more or less than an array of arrays.
The object a is of type int[2][2], or 2-element array of 2-element array of int.
Any expression of array type is, in most but not all contexts, implicitly converted to ("decays" to) a pointer to the array object's first element. So the expression a, unless it's the operand of unary & or sizeof, is of type int(*)[2], and is equivalent to &a[0] (or &(a[0]) if that's clearer). It becomes a pointer to row 0 of the 2-dimensional array. It's important to remember that this is a pointer value (or equivalently an address), not a pointer object; there is no pointer object here unless you explicitly create one.
So looking at the several expressions you asked about:
&a is the address of the entire array object; it's a pointer expression of type int(*)[2][2].
a is the name of the array. As discussed above, it "decays" to a pointer to the first element (row) of the array object. It's a pointer expression of type int(*)[2].
*a dereferences the pointer expression a. Since a (after it decays) is a pointer to an array of 2 ints, *a is an array of 2 ints. Since that's an array type, it decays (in most but not all contexts) to a pointer to the first element of the array object. So it's of type int*. *a is equivalent to &a[0][0].
&a[0] is the address of the first (0th) row of the array object. It's of type int(*)[2]. a[0] is an array object; it doesn't decay to a pointer because it's the direct operand of unary &.
&a[0][0] is the address of element 0 of row 0 of the array object. It's of type int*.
All of these pointer expressions refer to the same location in memory. That location is the beginning of the array object a; it's also the beginning of the array object a[0] and of the int object a[0][0].
The correct way to print a pointer value is to use the "%p" format and to convert the pointer value to void*:
printf("&a = %p\n", (void*)&a);
printf("a = %p\n", (void*)a);
printf("*a = %p\n", (void*)*a);
/* and so forth */
This conversion to void* yields a "raw" address that specifies only a location in memory, not what type of object is at that location. So if you have multiple pointers of different types that point to objects that begin at the same memory location, converting them all to void* yields the same value.
(I've glossed over the inner workings of the [] indexing operator. The expression x[y] is by definition equivalent to *(x+y), where x is a pointer (possibly the result of the implicit conversion of an array) and y is an integer. Or vice versa, but that's ugly; arr[0] and 0[arr] are equivalent, but that's useful only if you're writing deliberately obfuscated code. If we account for that equivalence, it takes a paragraph or so to describe what a[0][0] means, and this answer is probably already too long.)
For the sake of completeness the three contexts in which an expression of array type is not implicitly converted to a pointer to the array's first element are:
When it's the operand of unary &, so &arr yields the address of the entire array object;
When it's the operand of sizeof, so sizeof arr yields the size in bytes of the array object, not the size of a pointer; and
When it's a string literal in an initializer used to initialize an array (sub-)object, so char s[6] = "hello"; copies the array value into s rather than nonsensically initializing an array object with a pointer value. This last exception doesn't apply to the code you're asking about.
(The N1570 draft of the 2011 ISO C standard incorrectly states that _Alignof is a fourth exception; this is incorrect, since _Alignof can only be applied to a parenthesized type name, not to a expression. The error is corrected in the final C11 standard.)
Recommended reading: Section 6 of the comp.lang.c FAQ.
Because all expressions are pointing to the beginning of the array:
a = {{a00},{a01},{a10},{a11}}
a points to the array, just because it is an array, so a == &a[0]
and &a[0][0] is positioned at the first cell of the 2D array.
+------------------------------+
| a[0][0] <-- a[0] <-- a | // <--&a, a,*a, &a[0],&a[0][0]
|_a[0][1]_ |
| a[1][0] <-- a[1] |
| a[1][1] |
+------------------------------+
It is printing out the same values because they all are pointing to the same location.
Having said that,
&a[i][i] is of type int * which is a pointer to an integer.
a and &a[0] have the type int(*)[2] which indicates a pointer to an array of 2 ints.
&a has the type of int(*)[2][2] which indicates a pointer to a 2-D array or a pointer to an array of two elements in which each element is an array of 2-ints.
So, all of them are of different type and behave differently if you start doing pointer arithmetic on them.
(&a[0][1] + 1) points to the next integer element in the 2-D array i.e. to a[0][1]
&a[0] + 1 points to the next array of integers i.e. to a[1][0]
&a + 1 points to the next 2-D array which is non-existent in this case, but would be a[2][0] if present.
You know that a is the address of the first element of your array and according to the C standard, a[X] is equal to *(a + X).
So:
&a[0] == a because &a[0] is the same as &(*(a + 0)) = &(*a) = a.
&a[0][0] == a because &a[0][0] is the same as &(*(*(a + 0) + 0))) = &(*a) = a
A 2D array in C is treated as a 1D array whose elements are 1D arrays (the rows).
For example, a 4x3 array of T (where "T" is some data type) may
be declared by: T a[4][3], and described by the following
scheme:
+-----+-----+-----+
a == a[0] ---> | a00 | a01 | a02 |
+-----+-----+-----+
+-----+-----+-----+
a[1] ---> | a10 | a11 | a12 |
+-----+-----+-----+
+-----+-----+-----+
a[2] ---> | a20 | a21 | a22 |
+-----+-----+-----+
+-----+-----+-----+
a[3] ---> | a30 | a31 | a32 |
+-----+-----+-----+
Also the array elements are stored in memory row after row.
Prepending the T and appending the [3] to a we have an array of 3 elements of type T. But, the name a[4] is itself an array indicating that there are 4 elements each being an array of 3 elements. Hence we have an array of 4 arrays of 3 elements each.
Now it is clear that a points to the first element (a[0]) of a[4] . On the Other hand &a[0] will give the address of first element (a[0]) of a[4] and &a[0][0] will give the address of 0th row (a00 | a01 | a02) of array a[4][3]. &a will give the address of 2D array a[3][4]. *a decays to pointers to a[0][0].
Note that a is not a pointer to a[0][0]; instead it is a pointer to a[0].
Hence
G1: a and &a[0] are equivalent.
G2: *a, a[0]and &a[0][0] are equivalent.
G3: &a (gives the address of 2D array a[3][4]).
But group G1, G2 and G3 are not identical although they are giving the same result (and I explained above why it is giving same result).
This also means that in C arrays have no overhead. In some other languages the structure of arrays is
&a --> overhead
more overhead
&a[0] --> element 0
element 1
element 2
...
and &a != &a[0]
Intuitively, now the reason is clear behind the output. But, considering how pointers are implemented in C, I can't understand how a and &a are equal. I am assuming that there is a variable a in memory which points to the array(and the starting address of this array-memory-block would be the value of this variable a).
Well, no. There is no such thing as an address stored anywhere in memory. There is only memory allocated for the raw data, and that's it. What happens is, when you use a naked a, it immediately decays into a pointer to the first element, giving the impression that the 'value' of a were the address, but the only value of a is the raw array storage.
As a matter of fact, a and &a are different, but only in type, not in value. Let's make it a bit easier by using 1D arrays to clarify this point:
bool foo(int (*a)[2]) { //a function expecting a pointer to an array of two elements
return (*a)[0] == (*a)[1]; //a pointer to an array needs to be dereferenced to access its elements
}
bool bar(int (*a)[3]); //a function expecting a pointer to an array of three elements
bool baz(int *a) { //a function expecting a pointer to an integer, which is typically used to access arrays.
return a[0] == a[1]; //this uses pointer arithmetic to access the elements
}
int z[2];
assert((size_t)z == (size_t)&z); //the value of both is the address of the first element.
foo(&z); //This works, we pass a pointer to an array of two elements.
//bar(&z); //Error, bar expects a pointer to an array of three elements.
//baz(&z); //Error, baz expects a pointer to an int
//foo(z); //Error, foo expects a pointer to an array
//bar(z); //Error, bar expects a pointer to an array
baz(z); //Ok, the name of an array easily decays into a pointer to its first element.
As you see, a and &a behave very differently, even though they share the same value.