-3

What is the difference between these 2 prints, I got the same address in both of them :

int main(void)
{
    int arr[2][3] = {{1,2,3},{4,5,6}};
    printf("%p\n", arr);
    printf("%p\n", *(arr));
}

3 Answers3

2

arr is an array of 2 arrays of a 3 int. Consider these three things:

  • The array arr.
  • The first subarray of arr, also called arr[0].
  • The first element of arr[0], also called arr[0][0].

These three things start in the same place. The first subarray in arr is at the beginning of arr, so it starts where arr starts. And the first element of arr[0] is at the beginning of arr[0], and it is at the beginning of arr. Since the three things all start in the same place, it is not surprising that they appear to thace the same address.

Now, let’s look at what you printed. First, when printing a pointer, you ought to convert it to void *, as in printf("%p\n", (void *) arr);.

That said, printf(… arr) prints the address of arr[0]. Why arr[0] and not arr? Because, when used in an expression like this, an array is automatically converted to a pointer to its first element. So arr is automatically converted to a pointer to arr[0], and this is what the printf prints.

Similarly, printf(… *(arr)) prints the address of arr[0][0]. This is because, as above, arr is converted to a pointer to arr[0]. Then, since it is a pointer to arr[0], *(arr) applies * to that pointer, and the result is arr[0]. Since arr[0] is an array, it is also converted to a pointer to its first element. So the result is a pointer to arr[0][0] and that is what printf prints.

So, you are printing the address of arr[0] and the address of arr[0][0]. Since they start in the same place, it is not surprising the address is the same.

(It is not actually required that printing the addresses would produce the same string. The C standard allows an implementation to represent addresses in multiple ways. So it is possible that printing two different pointers to the same address could result in different output. That is fairly rare in modern C implementations.)

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

Except when it is the operand of the sizeof or the unary & operator, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" is converted ("decays") to an expression of type "pointer to T", and the value of the expression is the address of the first element of the array.

Given the declaration

int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};

the memory layout will be

   +---+
a: | 1 | a[0][0]
   +---+ 
   | 2 | a[0][1]
   +---+
   | 3 | a[0][2]
   +---+
   | 4 | a[1][0]
   +---+
   | 5 | a[1][1]
   +---+
   | 6 | a[1][2]
   +---+

So, one thing to notice - the address of a will be the same as the address of a[0], which will be the same as the address of a[0][0]. The address of a[1] will be the same as the address of a[1][0].

The expression a has type "2-element array of 3-element array of int", so unless it's the operand of & or sizeof, the type of the expression will "decay" to "pointer to 3-element array of int (int (*)[3]), and its value will be the address of the first element of a (&a[0]).

The expression *a has type "3-element array of int", so unless it is the operand of & or sizeof, the type of the expression will "decay" to "pointer to int, and the value of expression will be the address of the first element of *a (&(*a)[0], which is equivalent to &a[0][0]).

As mentioned above, the address of a is the same as the address of a[0], which is the same as the address of a[0][0]. In fact, all of the following expressions evaluate to the same address: &a, a, *a, a[0], &a[0], &a[0][0], although the types of the expressions are different. See the following table:

Expression        Type          "Decays" to        Value
----------        ----          -----------        -----
         a        int [2][3]    int (*)[3]         Address of a[0]
        *a        int [3]       int *              Value of a[0]
        &a        int (*)[2][3] n/a                Address of a
      a[i]        int [3]       int *              Value of a[i]
     *a[i]        int           n/a                Value of a[i][0]
     &a[i]        int *         n/a                Address of a[i]
   a[i][j]        int           n/a                Value of a[i][j]
  &a[i][j]        int *         n/a                Address of a[i][j]
John Bode
  • 119,563
  • 19
  • 122
  • 198
0

arr without indices is basically a pointer to the zeroeth element of the array, in context of your question there is no difference

arr <==> *arr

that is the reason you are getting the same address, In the next stage lets, we want to access the array elements then one method is trivial arr[i][j] or you can implement it like this in using pointer *(*(arr + i) + j), now the implementation may seem more different from each other but they are both accessing the same address just like in your case, so in this example also there address will be same, and same for all such cases.

Shubham Pandey
  • 111
  • 1
  • 1
  • 9