3

Considering this declaration:

int array[] = ....;

I know that &array[0] has the address of the first element as its value.

But what about &array? I tried this in my program and it also returned the address of the first element. So what's the difference?

Fred
  • 111
  • 1
  • 6
  • My textbook says that the value of &array should be unknown. But my compiler does assign the address of the first element to &array. – Fred Mar 01 '19 at 04:59
  • 1
    It sounds like the textbook is wrong, although there are interpretations in which that statement could be true. `&array[0]` is a pointer to the first element, and `&a` is a pointer to the array. Since the array and its first element start at the same place, these ultimately point to the same address, although they have different types. If they are both converted to `char *`, they must compare equal according to the rules of C. However, when they are different types, they may have different representations. In that sense, `&array` may differ from `&array[0]`, so it is not entirely known. – Eric Postpischil Mar 01 '19 at 05:19

2 Answers2

5

Try "difference between 'A', 65LL and 65.0?

All have values that equate to each other (assuming ASCII), yet are of different types and likely various bit widths and encodings.

Now "difference between &array and &array[0]"

Both have values that equate to each other as the point to the same location in memory, yet they differ in type: Pointer to an int array versus pointer to an int.

int a[] = {1,2,4};
// &a is a `pointer to array 3 of int`

A common effect of that type difference is with pointer math

printf("%p\n", (void*) (&a[0] + 1));  // next `int` address
printf("%p\n", (void*) (&a + 1));     // one past end of array address

[Advanced]: Although commonly the 2 pointers employ the same encoding and size, in C, they could also differ in encoding and size while still pointing to the same address.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • The difference is `type` becomes critical when attempting to pass the pointer as a parameter or specify the return type to a function. – David C. Rankin Mar 01 '19 at 06:18
  • Actually, is `&a + 1` ("one past end of array address") legal? I know that `a[3]` is legal, but from what part of the standard does it follow that `&a + 1` is legal? – Lover of Structure May 15 '23 at 06:35
  • @LoverofStructure Forming the address `&a + 1` is legal. Attempting to de-reference that address to the item it points to is _undefined behavior_ (UB). `&a + 1` is one array passed the array `a[]`. – chux - Reinstate Monica May 16 '23 at 02:32
  • According to [this answer](https://stackoverflow.com/a/988408/2057969) (and also my own reading of the standard), `&a[last_index]+1` is legal, but pointer arithmetic is in this case defined only for `int *`, not for the pointer to the containing array (type: `int (*)[]`) unless it's part of a larger array. Are you absolutely sure? If `&a + 1` were legal, `(char *)(&a + 1)` and `(char *)(&a[last_index]+1)` would have the same value, but I don't see why the former is legal according to the standard. – Lover of Structure May 16 '23 at 07:50
  • 1
    @LoverofStructure "Are you absolutely sure?" --> Yes. "6.5.6 Additive operators ... For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type." C17 § 6.5.6 7. Did you try compiling `&a + 1`? – chux - Reinstate Monica May 16 '23 at 08:37
  • I was wrong, and you are right! Thanks for pointing me to that clause. – Lover of Structure May 16 '23 at 15:01
2

When you declare the array of ints, as you did int array[] = { 1, 2, 3 }; etc, what the compiler has done there is reserve space for (in this case) three integers in a row "on the stack" (the memory space where local variables are kept during the execution of a function). The name for that space is array.

Taking the address of the first element, like &array[0], gives you the address of the first of those integers, as you expect. That address points to the small chunk of memory within the function's stack frame.

In the second case, you're asking for the address of "the variable called array", right? Well, that variable is... those same three integers on the stack. And the address of that thing is the same as the address of the first element. That's why those values are the same.


You note that your textbook says that the latter version is actually unknown. I'm not a standards expert on this, but that makes some sense-- it's not really idiomatic to use that second form, because you can just say array which also represents the same thing and is more sensible.

However, things change if you allocate that array dynamically. If you do this:

int * dynamic_array = malloc(3 * sizeof(int));

... then you've still created an "array" in practice, but the storage for those three integers is not on the stack anymore; it's been allocated dynamically from the heap. In this case, &dynamic_array[0] will still give you the address of the first element. That address is the same as the value which is contained inside the variable dynamic_array. Note in this case this is not the same as saying &dynamic_array. Taking the address of the pointer dynamic_array here would give you the address of the pointer on the stack, (i.e., an int **).

Ben Zotto
  • 70,108
  • 23
  • 141
  • 204
  • 1
    `&array` is not a `int **`. – chux - Reinstate Monica Mar 01 '19 at 05:07
  • The OP says the book says `&array` is unknown, not undefined. This cannot be entirely correct, as `(char *) &array == (char *) &array[0]` must be true in C if `array` does indeed identify an array, not a pointer. – Eric Postpischil Mar 01 '19 at 05:20
  • @chux Sure it is if `array` is a stack pointer to a dynamically allocated chunk of memory. I edited the variable names to be different in the second example so this is clear. – Ben Zotto Mar 01 '19 at 06:12