tags:

views:

156

answers:

4

I am surprised to see this code segment print the same address for all the three pointers.

int main(int argc,char *argv[])
{
   int arr[3][3];
   printf("%p\n%p\n%p\n",arr,*arr,arr[0]);
   return 0;
}

Why this is so ?

+3  A: 

See So what is meant by the ``equivalence of pointers and arrays'' in C?

The address of an array is the address of its first element. And, arr[i] is equivalent to *(arr + i) for any array arr. Therefore, arr[0] is the same as *(a + 0).

Sinan Ünür
arr[0] = *arr for all arrays that should have been the obvious bit. The surprising change for multidimensional arrays is that arr = *arr which only holds for multi-dimensional arrays due to how C treats them and lays them out in memory.
Mark
+2  A: 

Because an array's address is equal to the starting element's address.

Which means, address of arr[1] is equal to address of arr + 1 and address of *(arr + 1).

Ruel
Can downvoter(s) please explain? Thanks.
Ruel
Its wrong but I'm not downvoting because of the unexplained downvotes. `arr[1]` is not equivalent to `arr + 1` nor `*arr + 1` but rather `*(arr + 1)`
mathepic
dreamlax
@mathepic, in terms of printing %p, it is. Not talking about the values though, editing my answer.
Ruel
Ruel
dreamlax
I see, thanks for the clarification.
Ruel
@Ruel: And now I can +1! :)
dreamlax
+2  A: 

C lays out multidimentional arrays flat if at least all but the last dimension is known at compile time - so an int[3][3] is actually just and int[9] array in memory - only the type is different.

So, since an array is silently converted to a pointer to its first element when used in most expressions *arr is always equivalent to arr[0] for all arrays. In this instance, arr (two levels of indirection to int) is a pointer to the first int[3] array, *arr==arr[0] (1 level of indirection to int) is a pointer to the first integer in the first int[3] array, since the whole structure is 'flat' this first int[3] starts at exactly the same place as the int[3][3] array.

Its a little confusing, but in memory it is just 9 integers in a row that the compiler 'knows' should be treated as blocks of 3

if the cells are those shown below:

|0|1|2|3|4|5|6|7|8|

then arr is a pointer to |0|, arr+1 is a pointer to |3| and arr+2 is a pointer to |6|

arr[0] is ALSO a pointer to |0|, arr[0]+1 is a pointer to |1|, arr[0]+2 is a pointer to |2| and so on... Since arr[0] is always identical to *arr for any array, *arr is ALSO a pointer to |0|

tobyodavies
dreamlax
True, sizeof does treat arrays specially, but when *dereferencing* using the unary `*` operator it is safe to assume as much. Effectively an array is a pointer with some compile-time-only metadata that the compiler can use to evaluate some pseudo-functions like sizeof
tobyodavies
Your statement is still incorrect. In C99 the `sizeof` operator must also return the size of a variable length array. `sizeof` is not a pseudo-function it is an *operator*. An array is converted to a pointer type pointing to its initial element (see §6.3.2.1 paragraph 3 of the C standard).
dreamlax
`arr` is only converted to a pointer type when it is used in an expression and when it is not the operand of ``).
dreamlax
you are right, i apologise... i hadn't thought about that... still, in terms of dereferencing the array i.e. the only 2 operators used on it are subscript and unary `*` it is effectively just a pointer.
tobyodavies
tobyodavies
@tobyodavies: It's still not quite the same. An array type is its own type just like a pointer type is its own type. An array type can be converted to a pointer type, just like on many implementations a pointer type can be converted to an scalar integer type. You can't assign a value to an array because not a modifiable lvalue. This carries different semantics to a const-qualified pointer.
dreamlax
Hmmm, ok, i guess it is just another instance of C's weak typing...
tobyodavies
i've rephrased part of the answer to reflect, thank you for the clarification... My C is less good than i thought :P
tobyodavies
`arr` does not have type `int **`, as this answer incorrectly states. `arr` decays to type `int (*)[3]`, which is completely different from `int **`. Not even close.
AndreyT
I meant `**arr` is of type int i.e. decays to `int(*)[3]`, `*` of which decays again to `int*`... rephrased to clarify - i was just using it to count indirections
tobyodavies
A: 

arr is the address of the first element in the array which is also the address of the first row of the array due to how C lays out multidimensional arrays in memory.

arr[0] returns a pointer to the first row so is equivalent to arr

*arr = arr[0] as with all C pointers

basically they are all the same because of the way C lays out multidimensional arrays, the address of the beginning of the array is also the address of the first row of the array.

part of this confusion is that while for a 1 dimensional array, arr[], arr can be treated as a pointer as if it were defined '*arr'. This isn't true for multidimensional arrays. arr[][] can't be treated as a double pointer, as if it were defined **arr. they are very different data types.

Mark