zippo
is not a pointer. It's an array of array values. zippo
, and zippo[i]
for i
in 0..4 can "decay" to a pointer in certain cases (particularly, in value contexts). Try printing sizeof zippo
for an example of the use of zippo
in a non-value context. In this case, sizeof
will report the size of the array, not the size of a pointer.
The name of an array, in value contexts, decays to a pointer to its first element. So, in value context, zippo
is the same as &zippo[0]
, and thus has the type "pointer to an array [2] of int
"; *zippo
, in value context is the same as &zippo[0][0]
, i.e., "pointer to int
". They have the same value, but different types.
I recommend reading Arrays and Pointers for answering your second question. The pointers have the same "value", but point to different amounts of space. Try printing zippo+1
and *zippo+1
to see that more clearly:
#include <stdio.h>
int main(void)
{
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
printf("%lu\n", (unsigned long) (sizeof zippo));
printf("%p\n", (void *)(zippo+1));
printf("%p\n", (void *)(*zippo+1));
return 0;
}
For my run, it prints:
32
0xbffede7c
0xbffede78
Telling me that sizeof(int)
on my machine is 4, and that the second and the third pointers are not equal in value (as expected).
Also, "%p"
format specifier needs void *
in *printf()
functions, so you should cast your pointers to void *
in your printf()
calls (printf()
is a variadic function, so the compiler can't do the automatic conversion for you here).
Edit: When I say an array "decays" to a pointer, I mean that the name of an array in value context is equivalent to a pointer. Thus, if I have T pt[100];
for some type T
, then the name pt
is of type T *
in value contexts. For sizeof
and unary &
operators, the name pt
doesn't reduce to a pointer. But you can do T *p = pt;
—this is perfectly valid because in this context, pt
is of type T *
.
Note that this "decaying" happens only once. So, let's say we have:
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
Then, zippo
in value context decays to a pointer of type: pointer to array[2] of int
. In code:
int (*p1)[2] = zippo;
is valid, whereas
int **p2 = zippo;
will trigger an "incompatible pointer assignment" warning.
With zippo
defined as above,
int (*p0)[4][2] = &zippo;
int (*p1)[2] = zippo;
int *p2 = zippo[0];
are all valid. They should print the same value when printed using printf("%p\n", (void *)name);
, but the pointers are different in that they point to the whole matrix, a row, and a single integer respectively.