john987
john987

Reputation: 65

In C, why is dereferenced array pointer identical to the pointer itself?

In the code below, I declare an int array "a" and then a pointer to the entire array "ap":

int main(){
        int a[3] = {10, 100, 1000};
        int (*ap)[] = &a;

        printf("%p\n", ap);
        printf("%p\n", *ap);
        printf("%d\n", **ap);

        return 0;
}

The first print of ap shows that it is actually a pointer to the first value of the array. OK.
But in the second print, ap is dereferenced and, yet, the value is the same: pointer to the first value of the array.
It's only after a "double dereferencing" that I get the value of the first array element (10 in my example):

0x7fff193310cc
0x7fff193310cc
10

Why is that so?
Thanks a lot!

Upvotes: 5

Views: 102

Answers (4)

programmer
programmer

Reputation: 679

+------+---------+----------+
|  10  |   100   |    1000  |  
+------+---------+----------+
^  ^ ^  
|  | |
|  | +------+
|  +---+    +--+
&ap    |       |
       *ap     **ap
  • &ap points to the base address of the array, its type is int (*)[3] (pointer to array with 3 int elements).

  • *ap points to the first element of the array, its type is int * (pointer to int).

  • **ap yields the value stored at the address of the first element, its type is int.


But in the second print, ap is dereferenced and, yet, the value is the same: pointer to the first value of the array.

The name of an array in C usually yields the address of the first element of the array.

However when you use the & operator in an expression such as &arrayname, it yields a pointer of type T(*)[size] instead of "pointer to the first element".

This means &a and a both have the same value, but they have completely different types, hence why ap and *ap also have the same value but different types.

Upvotes: 2

Vlad from Moscow
Vlad from Moscow

Reputation: 311028

You declared a pointer to an object of the type int[3].

    int (*ap)[] = &a;

So the call of printf prints the address of the object of the type int[3]

    printf("%p\n", ap);

Dereferencing the pointer you get an array of an unknown size due to this declaration of the pointer int (*ap)[]. Array designators used in expressions with rare exceptions are converted to pointers to their first elements. So the address of the first element of the array is outputted in this call of printf

printf("%p\n", *ap);

The addresses of the array itself and of its first element are equal each other.

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409196

When you do *ap it's basically the same as doing *(&a), which is in essence plain a.

And as arrays decays to pointers to their first elements, plain a is the same as &a[0].

Now here's the interesting thing: The location of the array a and the location of the first element of a is the exact same location.

It's easy to see if we draw it out:

+------+------+------+
| a[0] | a[1] | a[2] |
+------+------+------+
^
|
&a[0]
|
&a

See how both &a[0] and &a are pointing to the same location?

But also remember that while both &a[0] and &a are pointing to the same location, they have very different types:

  • &a[0] will have the type int *
  • &a will have the type int (*)[3]

Upvotes: 5

Eric Postpischil
Eric Postpischil

Reputation: 222933

ap is a pointer to an array. In the program execution you observed, the array starts at address 7FFF193310CC16.

Since ap is a pointer to an array, *ap is an array. When an array is used in an expression other than as the operand of unary &, the operand of sizeof, or as a string literal used to initialize an array, it is automatically converted to a pointer to its first element. Therefore, *ap is converted to a pointer to (*ap)[0]. Naturally, the first element of an array starts in the same place the array does, since it is the first thing in the array, so its address is 7FFF193310CC16.

Since *ap is automatically converted to a pointer to (*ap)[0], **ap is the thing it points to, which is (*ap)[0], so it is the first element of the array, not a pointer.

Note that, to have behavior defined by the C standard when printing a pointer, you should convert it to void *:

printf("%p\n", (void *) ap);
printf("%p\n", (void *) *ap);

Upvotes: 2

Related Questions