0

This is a bidimensional array. I understand that the name of the array points to the first element in the array, that is &array[0][0]. But when I try to print, the name of the array, the address of the array and the value of the array are all the same.

#include <stdio.h>
int main(void)
{
    int array[4][2]={1,2,3,4,5,6,7,8};
    printf("%d    %d\n",
           &array[0][0], array[0][0]);
    printf("%d    %d    %d    %d\n",
           array, &array, *array, **array);
}

OUTPUT

2686704    1
2686704    2686704    2686704    1
user3646717
  • 1,095
  • 2
  • 12
  • 21

4 Answers4

1

In your code (corrected):

#include <stdio.h>
int main(void)
{
    int array[4][2] = {1,2,3,4,5,6,7,8};
    printf("%p    %d\n",
           (void *) &array[0][0], array[0][0]);
    printf("%p    %p    %p    %d\n",
           (void *) array, (void *) &array, (void *) *array, **array);
}

in the last printf() call:

  • array is a two-dimensional array of int, but in this context the name of an array decays to a pointer to its first element. Its first element is array[0], not array[0][0], as evidenced by the fact that:

    int * p = array;
    

    should give you a warning, while:

    int (*p)[2] = array;
    

    should not.

    Because of the way arrays are laid out in memory it is, however, also true that the address of array is the same as the address of array[0] which is the same as the address of array[0][0].

  • &array is the address of the array, which is the same as the address of its first element...and so on.

  • *array is equivalent to array[0]. The type of array[0] is array of int of size 2. Since array[0] is itself an array, it also here decays into a pointer to its first element, which as explained is the same address as &array, and the same address array decays to, here.

  • **array is equivalent to array[0][0] which, finally, is an actual int, not an array, and therefore doesn't decay to any kind of address, it's just the value 1.

That's why the first three expressions all evaluate to the same address.

Note that %p is for pointers, and because printf() is a variadic function, the compiler cannot implicitly convert your pointers to void * like it normally would, because it doesn't know printf() is expecting a void * for a %p specifier, so you should explicitly cast them to void *. In reality, you'll probably be looking a long time to find a modern desktop computer where void *, int *, int (*)[2], and int (*)[4][2] don't have the exact same representation, but being correct is better than not being correct.

Crowman
  • 25,242
  • 5
  • 48
  • 56
0

You do not have a pointer variable. It is an array (expression), which is internally converted into the address of the first element in most contexts.

A pointer would be int (*arrptr)[4][2] = &array;. The difference is rather good explained in the C FAQ

int array[4][2]={1,2,3,4,5,6,7,8};
int (*ptr1)[4][2]=&array;
static int (*ptr2)[4][2];
ptr2=&array;
printf("%p                   %d\n",
        &array[0][0], array[0][0]);
printf("%p    %p      %p     %d\n",
        array,&array, *array,**array);
printf("%p    %p      %p     %d\n",
        ptr1, &ptr1,  *ptr1, ***ptr1);
printf("%p    %p      %p     %d\n",
        ptr2, &ptr2,  *ptr2, ***ptr2);

0xbfbfec24                                1
0xbfbfec24    0xbfbfec24    0xbfbfec24    1
0xbfbfec24    0xbfbfec20    0xbfbfec24    1
0xbfbfec24    0x804970c     0xbfbfec24    1
                      ^^

Here you see that the pointer is a different address in the stack and the static pointer an even more different address in the heap.

eckes
  • 10,103
  • 1
  • 59
  • 71
  • 1
    using `%u` to print pointers causes undefined behaviour (at least use `%p`, strictly speaking the pointer should also be cast to `void *`). – M.M Dec 29 '14 at 05:33
  • @MattMcNabb I know (i wrote this in my comment above), I just did not want to derivate too much from the original example. – eckes Dec 29 '14 at 05:35
  • 2
    Deviating from the original example in order to correct it is always appropriate. Especially when the original example didn't even use `%u`. – Crowman Dec 29 '14 at 05:43
  • @PaulGriffiths thanks, I used %p and changed the output - I skip the casts. – eckes Dec 29 '14 at 05:49
  • 1
    "It is an array, which is internally treated as its actual address." Not exactly. An array expression is, in most contexts, *converted* to the address of its first element. – Keith Thompson Dec 29 '14 at 06:27
0

They aren't the same thing.

An array is an object consisting of a sequence of one or more contiguous elements, all of the same type. A 2-dimensional array is nothing more or less than an array of arrays.

The name of an array is an expression. Like any expression of array type, it is, in most but not all contexts, implicitly converted to a pointer to the array's first element. The exceptions are when it's the operand of sizeof (sizeof arr yields the size of the array object, not the size of a pointer) and when it's the operand of unary & (&arr yields the address of the entire array).

The address of an array is like the address of any object. It refers to a particular memory address, and it has a type: pointer to the array type. For example, given:

int arr[10];

the expression arr (if it's not the operand of & or sizeof) yields the address of arr[0], and is of type int*. The expression &arr yields the address of the entire array; it's the same memory location, but it's of type int (*)[10], or "pointer to array of 10 ints".

The value of an array is generally not something that's you can directly refer to. It consists of the values of the elements of the array.

Now let's look at your program:

#include <stdio.h>
int main(void)
{
    int array[4][2]={1,2,3,4,5,6,7,8};

This is more clearly written as:

    int array[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};


    printf("%d    %d\n",
           &array[0][0], array[0][0]);

array[0][0] is an int object, so &array[0][0] is its address, and is of type int*. The correct way to print an address (pointer value) is to use the %p format; it expects an argument of type void*, so you should convert it.

    printf("%p    %d\n", (void*)&array[0][0], array[0][0]);

    printf("%d    %d    %d    %d\n",
           array, &array, *array, **array);

array is an expression of array type, so it "decays" to a pointer to that array's first element. That element is of type int[2], so the pointer is of type int(*)[2]. Again, you should use %p and convert to void*.

&array is the address of the entire array. It's of type int(*)[4][2].

In *array, the subexpression array decays to a pointer. * then dereferences that pointer, which gives us an object of type int[2] (the first element of the array). That's an expression of array type, so it decays again to a pointer to that array's first element. It's of type int*.

In **array, *array is evaluated as above; it's a pointer to an int object. The next * dereferences that pointer, yielding an int value.

All the pointer values you've printed point to the same memory address, but they're variously of type int*, int(*)[2], or int(*)[2][4]. Each of these pointers, when converted to void*, yields the same value, and all of them

}

Putting this together, here's a corrected version of your program:

#include <stdio.h>
int main(void)
{
    int array[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
    printf("%p    %d\n",
           (void*)&array[0][0], array[0][0]);
    printf("%p    %p    %p    %d\n",
           (void*)array, (void*)&array, (void*)*array, **array);
}

The output on my (64-bit) system is:

0x7fffc5070b30    1
0x7fffc5070b30    0x7fffc5070b30    0x7fffc5070b30    1

The relationship between arrays and pointers in C can be confusing. Much of the confusion can be cleared up by reading section 6 of the comp.lang.c FAQ.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
-3

The internal representation of Array is as follows. Arrays are nothing but constant pointers. They are represented as continuous memory locations.

Sample example

So if we access the array as A[1] it is converted into *(A + 1) i.e A here points to address of first element and 1 represents offset. If the array is of type int then 1 represents the sizeof int for e.g consider size of int as 4B. So 4 bytes is added to A which will now make it points to second element in the array A. So in 2D array it would be represented as *(*(A + i) + j) where i is row and j is column. So based on it you will get the output as mentioned above

Crowman
  • 25,242
  • 5
  • 48
  • 56
Jigar
  • 300
  • 4
  • 13
  • The `A + i` part of your `*(*(A + i) + j)` arithmetic actually relies on pointers and arrays not being the same. If `i` was measured in terms of `sizeof(int)` or even `sizeof(int *)`, then you'd be lucky to get the element you were after. – Crowman Dec 29 '14 at 05:43