I'm new to C and trying to understand the following code
#include <stdio.h>
int main() {
int i[3] = {1, 2, 3};
int* p = &i;
printf("%d\n", *p);
printf("%d\n", *(&i));
return 0;
}
What I thought was i
is a pointer to first element of the array, then '&i' must be a pointer to pointer. But here we have an assignment
int* p = &i;
C still allows it with a warning of int* differs in levels of indirections from int(*)[3]
. I thought this assignment shouldn't be allowed since it kinda weird.
Then the result of *p
is 1
, and it differs from *(&i)
which gives the address of the first element. I don't understand why it became like that. I tried to google for the warning above, assignment from pointer to address of array to int pointer, etc. but haven't found what I need.
Thank you for your time.
What I thought was 'i' is a pointer to first element of the array ...
Not quite correct. The variable i
may decay to a pointer to the first element under many circumstances, but i
itself is the integer array {1, 2, 3}
.
And, since there is no padding before the 1
, the address of i
is the same as the address of that 1
. The warning appears because you're using the pointer in a way that violates a constraint in the standard(1).
The ISO C17
standard (see 6.3.2.1 Lvalues, arrays, and function designators
) has this to say:
Except when it is the operand of the
sizeof
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.
This is very much a "unary &
operator" scenario hence it does not decay.
The reason why *(&i)
does not cause a similar issue is because:
i
variable is an lvalue (all array names are, they're just not modifiable lvalues that you can assign to) and it's type is therefore the full array;E
is an lvalue that is a valid operand of the unary &
operator, *&E
is an lvalue equal to E
" - hence its type is also the full array;sizeof
or &
), it decays to the pointer.In other words, the second and third lines below are equivalent, both of them decay before assigning and will not produce the warning you see with the non-decaying first and fourth lines. That fourth line is simply the exact same operation that was used to assign to p1
but with *&i
rather than just i
, both having the same (array) type:
int *p1 = &i ; // no decay.
int *p2 = i ; // decay.
int *p3 = *(&i) ; // decay.
int *p4 = &(*(&i)); // no decay.
(1) As per C17 6.5.16 Assignment operators
(and 6.7.9 Initialization
which references the former), the constraints do not allow for assignment or initialisation where the source object is an array. The only types are arithmetic, structure or union, or pointer. Arrays are an aggregate type, like structures and unions, but are not explicitly included.