The code is playing evil pointer games, without luck. You are passing a pointer having type int(*)[10]
to a function that wants a pointer having type int**
. The pointer you pass has as value the "base address" of the array.
So, when you dereference the int**
, it thinks at that address it gets an int*
, even though what it looks at is an int
object. And it writes the address returned from malloc
into that memory cell.
Back in main, you print out that cell. Note that it is the value of the array's first element, not the address of the array's first element. So what is printed is the integer value interpretation of the address you wrote in the called function.
What you do is undefined behavior: The function wants a int**
, so you have to give it an int**
,
Here is how i think you view the matter
- You hear someone say that an array name is a constant pointer to its first element
- You take the address of that pointer, cast away any const
- You happily write some other address into the pointer, and hope that it doesn't crash
- You use the array again, expecting it "overlays" now the uninitialized memory region that malloc created.
But that view is flawed. The first point is flawed the most, because an array name is not a constant pointer. If the first point were correct, your snippet would make a lot more sense, actually. But an array name will generate an address value that refers to its first element when you use it in an expression, except in very few cases (sizeof, address-of).
Because that address value is not generated when you use address-of, you will get a pointer to that array instead (which was exactly what you wrote with the address-of operator). Since it makes sense that an array and the first element of it has the same address, the address of an array happens to equal to the address of its first element. So what you actually did was writing into the first element, instead of writing into some pointer (that in reality isn't there).
Response to Comment
Consider what happens when the type of the array matters in practice (out of these experiments). You have an array whose elements are arrays themselves.
// array of 3 "array of 10 int"
int a[3][10];
So, by using a
in an expression other than &
and sizeof
, you will get a pointer to the first element, int(*)[10]
. This is crucial, because the following writes into an integer that's offset 2*sizeof(int)*10
bytes
a[2][0] = 1;
// (a + 2) refers to a offset by 2*sizeof(int)*10 bytes
If a
in that expression would give you an int**
, then the compiler would have no idea where it should store the integer 1
correctly into, because any size information about the element type is lost. It could surely store the size somewhere in memory, but where? In the array, there is no space for that. And in addition, sizeof
couldn't be able to give you a compile time result anymore.