When you use an array like a
in an expression, it usually goes through “pointer decay” which means that you get a pointer to the first element of the array.
So, a
has type int[3][4]
, and it decays to int (*)[4]
. When you write a+1
, you get the address of a[1]
… which is sizeof(*a)
bytes after a
, which is sizeof(int)*4
, which is 8 on your system.
When you use &
, pointer decay does not happen. &a
is not an array (it is already a pointer), so when you write &a+1
, you get the address “one past the end” of a
… which is sizeof(a)
bytes after a, which is sizeof(int)*12
, or 24 bytes on your system.
Note that, strictly speaking, the correct way to print pointers is with %p
.
printf("%p\n", a);
printf("%p, %p\n", a+1, &a+1);
(Technically, you also have to cast to char *
or void *
but that’s hardly ever important.)