First, the word on arrays ...
_Alignof it is the operand of 0 sizeof , _Alignof or unary & operators, or is a string literal used to initialize another array in the declaration, an expression of type "N-element array" from T "will be converted (" decay ") to expression type "pointer to T ", and the value of the expression will be the address of the first element in the array.
The &a expression is of type "pointer to a 10-element array from a 10-element array int " or int (*)[10][10] . The expression a is of the type "10-element array of a 10-element int array", which, according to the rule above, splits into a "pointer to a 10-element array int " or int (*)[10] . And finally, the expression *a (equivalent to a[0] ) has the type "10-element int array", which again, according to the rule above, splits into a "pointer to int ".
All three expressions have the same value, because the address of the array and the address of its first element are the same: &a[0][0] == a[0] == *a == a == &a , However, the types of expressions are different, which matters when doing pointer arithmetic. For example, if I have the following declarations:
int (*ap0)[10][10] = &a; int (*ap1)[10] = a; int *ip = *a;
then ap0++ will advance ap0 to point to the next 10x10 int array, ap1++ will advance ap1 to a pointer to the next array of 10 int elements (or a[1] ), and ip++ will advance ip to point to the next int ( &a[0][1] ).
**a equivalent to *a[0] , which is equivalent to a[0][0] . which is the value of the first element a and has type int and value 1 (note that only a[0][0] initialized to 1 , all other elements are initialized to 0 ).
Note that you must use %p to print pointer values:
printf("&a = %p\n", &a); printf(" a = %p\n", a); printf("*a = %p\n", *a);