0

Why does this code output: 1arr[0] and not &arr[0]?

My assumption is that after the assignment, ptr holds the address of &arr, which is a pointer to the first element of arr or arr[0].

So dereferencing the ptr should yield the value stored at that address, which is the memory location of the first element.

#include<stdio.h>

int main(void) {
    int arr[] = { 1 };
    int* ptr = &arr;
    printf("%d\n", *ptr);
    return 0;
}
andrey
  • 1,515
  • 5
  • 23
  • 39
  • 3
    `int* ptr = &arr;` - this is incompatible pointer assignment. `&arr` is of type `(int*)[1]` - that is a pointer to an array. It just happens that the value of it is the same as `&arr[0]`. So when you dereference `ptr` which has this value, you are getting the value of `arr[0]` – Eugene Sh. May 06 '21 at 18:15
  • 2
    Learn to love compiler warnings, they are your friends. The code you have created will produce a warning on any sane compiler. – SergeyA May 06 '21 at 18:20
  • gcc reports `int (*)[1]` in the warning. Is `(int*)[1]` the same? I believe not. The parens make the star mean the array not the int, so rather `int (*[])` –  May 06 '21 at 19:23
  • The code will produce an error on any correctly-configured compiler ; if you don't see this then I suggest changing settings – M.M May 06 '21 at 23:22
  • 1
    `(int*)[1]` is a syntax error; the type of `&arr` is `int(*)[1]`.. The parentheses serve to prevent the token sequence `int *` being parsed as *type-name* – M.M May 06 '21 at 23:23

2 Answers2

1

I added some print statements to your code:

#include<stdio.h>

int main(void) {
    int arr[] = { 1 };
    int *ptr = (int *)arr;
    printf("%p\n", (void *)arr);
    printf("%p\n", (void *)&arr);
    printf("%p\n", (void *)&arr[0]);
    printf("%p\n", (void *)ptr);
    printf("%p\n", (void *)&ptr);
    printf("%d\n", *ptr);
    return 0;
}

It prints:

0x7ffe3fe37aa4
0x7ffe3fe37aa4
0x7ffe3fe37aa4
0x7ffe3fe37aa4
0x7ffe3fe37a98
1

Which means arr and ptr are on the stack: ptr is at 0x7ffe3fe37a98 and has the value 0x7ffe3fe37aa4, which is where the arr is stored.

Note that arr and &arr have the same value. See this question: How come an array's address is equal to its value in C?

My assumption is that after the assignment, ptr holds the address of &arr, which is a pointer to the first element of arr or arr[0].

That is correct.

So dereferencing the ptr should yield the value stored at that address

Also correct.

which is the memory location of the first element.

No. Since ptr is pointing to the first element, dereferencing yields the first element, which is 1.

mkayaalp
  • 2,631
  • 10
  • 17
1

A couple of things...

First, a doesn't store the location of a[0]. There is no object a that is separate from the array element a[0]. Basically what you have in memory is

Address        
-------       +------+ 
 0x1000    a: | 0x01 | a[0]
              +------+

In other words, the address of an array is the same as the address of its first element.

Unless it is the operand of the sizeof or unary & operators, the expression a will be converted ("decay") from type "1-element array of int" (int [1]) to "pointer to int" (int *) and the value of the expression will be the address of the first element in the array.

This means that the expressions &a, a, and &a[0] all yield the same address value; it's just the types of the expressions are different:

Expression     Type        Decays to    
----------     ----        ---------
        &a     int (*)[1]
         a     int [1]     int *
     &a[0]     int *

Which brings us to this line:

int* ptr = &arr; // int * = int (*)[1] - assignment of incompatible types

The compiler should have yelled at you about that line. You may want to dial up the warning level.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • There are other expressions where arrays don't decay aside from `sizeof` and `&`. For example, `_Alignof`. – DarkAtom May 06 '21 at 22:21