EDIT
This is not a question on array decay from char [1]
and char *
. I know what array decay is for 1D arrays. It however seems different for char [1][1]
and char **
since they are not even compatible types.
I know that I can go from one of the types char [1]
and char *
to the other. However, it seems not as easy with char [1][1]
and char **
.
In my main
function I have:
int main(void) {
char a[1][1];
a[0][0] = 'q';
printf("a: %p\n", a);
printf("*a: %p\n", *a);
printf("**a: %p\n", **a);
}
I'm of course compiling with warnings and I know that gcc complains about the 6th line as **a
is actually of type char
and not a pointer type. However running the code shows that a
and *a
are actually the same pointer but **a
is as expected something else (0x71
which I assume is related to 'q'
in some way).
I'm trying to make sense of this and it seems that because *a
and a
are equal **a
must also be equal to a because **a = *(*a) = *(a) = *a = a
. It seems that the only error in this reasoning can be the types of a
, *a
, **a
.
How is a
actually stored in memory? If a
is a pointer to another memory location (in my case 0x7fff9841f250
) then surely *a
should be the value at that memory address which in my case is also 0x7fff9841f250
. So then **a
would be the value at 0x7fff9841f250
which is the same value as 'a'... It seems that I cannot view the 2D array char a[1][1]
as pointers in a way that makes sense. But then how can I think of this type? What is the type and what does a
, *a
, **a
, a[0]
, a[0][0]
actually mean?
I have already seen Incompatible pointer type but it does not explain what the operations *a
, **a
, a[0]
, a[0][0]
are actually doing.
a
defined as char a[1][1]
is an array of 1 array of 1 char
: it consists of a single byte of memory set aside by the compiler with automatic storage upon entering the scope of the function main
, ie: a single byte of the stack area with an address that happened to be 0x7fff9841f250
when you ran the program, but could be different for a different run or another day, with another compiler, on a different architecture or host...
This piece of memory uses that same space a single char
defined as char a;
or as an array of 1 char
defined as char a[1];
or as a 3D array defined as char a[1][1][1];
but the type is very different and the type determines how and when the memory is actually read as opposed to its address being taken.
The address of a
is also the address of the first row a[0]
and the address of the first element of the first row a[0][0]
.
a
is the name of the 2D array, when you pass a
to a function, it decays to a pointer to its first element, &a[0]
, which by definition is the address of the array but has type char (*)[1], pointer to arrays of 1 char
. Similarly a[0]
is an array, so passing a[0]
to a function actually passes the address of its first element &a[0][0]
, which is the same address but with a different type char *
.
The syntax *a
is evaluated the same way as a[0]
or *(a + 0)
, (and also more surprisingly *(0 + a)
, and 0[a]
). If a
was a pointer, its value would be read when you pass a
to printf
, but a
is an array so a
decays as &a[0]
and the address is passed without reading the memory. Similarly *a
becomes *&a[0]
or &a[0][0]
, ie: *a
passed as an argument to printf
is just the address of the single element a[0][0]
. The compiler generates code that computes the address, such as value of the stack pointer register plus 8.
Note these remarks:
printf("a: %p\n", a);
should be written printf("a: %p\n", (void *)a);
because a
decays as a pointer of type char (*)[1]
which might not be passed the same way nor have the same representation as void *
, the type expected by printf
for %p
.
printf("a: %p\n", *a);
should be written printf("a: %p\n", (void *)*a);
because *a
decays as a pointer of type char *
which is probably passed the same way and has the same representation as void *
, but still is a different type from the type expected by printf
for %p
.
printf("a: %p\n", **a);
has undefined behavior because **a
is a char
value, which is passed as an int
after promotion, but is definitely not the type expected by printf
for %p
. The behavior is undefined. The output is unpredictable and anything else can happen. 0x71
happens to be the ASCII code for 'q'
expressed in hexadecimal, but this behavior is not guaranteed. Some other output could be produced on a different system, with different compiler settings, at some other time, and anything else could happen. Writing printf("a: %p\n", (void *)**a);
would prevent the undefined behavior, but conversion from int
to void *
is implementation defined, so the behavior is still not guaranteed.
To summarize: An array has an address and some contents, whereas a pointer has a value that is an address.
Trivial comparison: