No *zippo
do not go to location 15 then find the value at this location.
If it was so then printf(" * ((int **) zippo) = %p\n", * ((int **) zippo) );
would output the same thing as printf(" *zippo = %p\n", *zippo);
and that is not the case.
When I run this code this is what I obtain :
#include <stdio.h>
int zippo[4][2] = {{2, 4}, {6, 8}, {1, 3}, {5, 7}};
int main(){
printf("zippo[0] = %p\n", (void *) (zippo[0]) );
printf(" zippo = %p\n", (void *) zippo);
printf(" *zippo = %p\n", (void *) (*zippo) );
printf(" **zippo = %d\n", (int) ( **zippo) );
printf(" * ((int **) zippo) = %p\n", (void *) (* ((int **) zippo) ));
}
This is what I obtain :
zippo = 0x804a040
*zippo = 0x804a040
**zippo = 2
* ((int **) zippo) = 0x2
I compiled this code using gcc -Wall -Wextra -Wpedantic -pedantic
to ensure that no warning is hidden and the option -m32
to have 32 bits adresses (same size as int).
I actually had a hard time understanding what is happening in there so I decided to have a look at the corresponding assembly code. using gcc -S file.c -o file.s
I obtain the following.
First variable declaration :
.globl zippo
.data
.align 32
.type zippo, @object
.size zippo, 32
zippo:
.long 2
.long 4
.long 6
.long 8
.long 1
.long 3
.long 5
.long 7
.section .rodata
.LC0:
.string "zippo[0] = %p\n"
.LC1:
.string " zippo = %p\n"
.LC2:
.string " *zippo = %p\n"
.LC3:
.string " **zippo = %d\n"
.LC4:
.string " * ((int **) zippo) = %p\n"
The correcsponding assembly for printf("zippo[0] = %p\n", (void *) (zippo[0]) );
:
movl $zippo, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
The correcsponding assembly for printf(" zippo = %p\n", (void *) zippo);
:
movl $zippo, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
The correcsponding assembly for printf(" *zippo = %p\n", (void *) (*zippo) );
movl $zippo, %esi
movl $.LC2, %edi
movl $0, %eax
call printf
The correcsponding assembly for printf(" **zippo = %d\n", (int) ( **zippo) );
:
movl $zippo, %eax
movl (%rax), %eax
movl %eax, %esi
movl $.LC3, %edi
movl $0, %eax
call printf
The correcsponding assembly for printf(" * ((int **) zippo) = %p\n", (void *) (* ((int **) zippo) ));
movl $zippo, %eax
movq (%rax), %rax
movq %rax, %rsi
movl $.LC4, %edi
movl $0, %eax
call printf
As you can notice here, for the 3 first printf, the corresponding assembly is exactely the same (what changes is LCx which corresponds to format).
Same thing for the last 2 printf.
My understanding is that as the compiler is aware that zippo
is a 2 dimensional array, and therefore knows that *zippo
is 1 dimensional array whose data starts at the adress of the first element.