53

Until now, I thought an array is the same as a pointer. But I found a weird case:

code

int array[5] = { 10,11,12,13,14};

std::cout << array << std::endl;
std::cout << &array << std::endl;
std::cout << &array[0] << std::endl;

int *pArray = new int[5];

std::cout << pArray << std::endl;
std::cout << &pArray << std::endl;
std::cout << &pArray[0] << std::endl;

output

0x7ffeed730ad0
0x7ffeed730ad0
0x7ffeed730ad0

0x7f906d400340
0x7ffeed730a30
0x7f906d400340

As you can see array and &array have the same value. But pArray and &pArray have different value. If array is same as pointer, address of array should be different from array. How can array and &array be the same? If array and &array are same, what is the address of the memory which holds the array values?

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
jinhwan
  • 1,207
  • 1
  • 13
  • 27
  • 22
    It's because an array is not a pointer. In the case of an array `&a` and `a` are the same thing. In the case of a pointer `p` is the address the pointer points to, and `&p` is the address where the pointer value is stored. – Jabberwocky Feb 21 '19 at 12:37
  • 7
    Here we can witness the inconsistency of the language. `new int[5]` should return a pointer to `int[5]`, not a pointer to `int`. – geza Feb 21 '19 at 12:42
  • related/duplicate: https://stackoverflow.com/questions/24104482/difference-between-pointer-to-an-array-and-pointer-to-the-first-element-of-an-ar – geza Feb 21 '19 at 12:45
  • @geza how is that different? A pointer is a pointer – Leonardo Herrera Feb 21 '19 at 14:50
  • @LeonardoHerrera: that's not that simple. This inconsistency has some consequences. Like, it is not that simple to get a pointer to the array from the pointer to the first element. – geza Feb 21 '19 at 15:14
  • @geza I don't follow. If you have a pointer to the first element of an array you have a pointer to the array itself. Care to elaborate? – Leonardo Herrera Feb 21 '19 at 15:28
  • @LeonardoHerrera: check out this: https://stackoverflow.com/questions/51552713/can-stdlaunder-be-used-to-convert-an-object-pointer-to-its-enclosing-array-poi. And maybe there are other questions about this issue. – geza Feb 21 '19 at 15:32
  • 3
    @geza That would require adding the (ugly) variable-length types, or alternative means of creating dynamic arrays. – HolyBlackCat Feb 21 '19 at 16:23
  • Ah, I stay clear from all that `reinterpret_cast` nonsense. – Leonardo Herrera Feb 21 '19 at 19:37

2 Answers2

88

Plain array decays to a pointer to its first element, it's equal to &array[0]. The first element also happens to start at the same address as the array itself. Hence &array == &array[0].

But it's important to note that the types are different:

  • The type of &array[0] is (in your example) int*.
  • The type of &array is int(*)[5].

The relationship between &array[0] and &array might be easier if I show it a little more "graphically" (with pointers added):

+----------+----------+----------+----------+----------+
| array[0] | array[1] | array[2] | array[3] | array[4] |
+----------+----------+----------+----------+----------+
^
|
&array[0]
|
&array

As an extra addendum, array decays to a pointer to its first element, that is array decays to &array[0] and will thus have the same type.


Things are different with pointers though. The pointer pArray is pointing to some memory, the value of pArray is the location of that memory. This is what you get when you use pArray. It is also the same as &pArray[0].

When you use &pArray you get a pointer to the pointer. That is, you get the location (address) of the variable pArray itself. Its type is int**.

Somewhat graphical with the pointer pArray it would be something like this

+--------+       +-----------+-----------+-----------+-----------+-----------+-----+
| pArray | ----> | pArray[0] | pArray[1] | pArray[2] | pArray[3] | pArray[4] | ... |
+--------+       +-----------+-----------+-----------+-----------+-----------+-----+
^                ^
|                |
&pArray          &pArray[0]

[Note the ... at the end of the "array", that's because pointers retains no information about the memory it points to. A pointer is only pointing to a specific location, the "first" element of the "array". Treating the memory as an "array" is up to the programmer.]

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Not sure that `(void*)&array` should be equal to `(void*)(&array[0])` BTW. (`&array[0]` and `array` should). – Jarod42 Feb 21 '19 at 13:47
  • @Jarod42 An array overlaps exactly with all individual elements of the array. There's no "padding" or "gaps" before, between or after the elements of the array. – Some programmer dude Feb 21 '19 at 13:55
  • 1
    I mean `int (&)[N]` decays to `int*` and so results in same pointer, `int (*)[N]` and `int*` are unrelated types. I don't think they have to be equal (once casted to "common" `void*`) even if it seems simpler to implement it that way. – Jarod42 Feb 21 '19 at 14:10
  • 1
    @Jarod42 I already mentioned the different types, but that doesn't matter. I don't have any quotes from the C++ specification unfortunately, but I distinctly remember that there's something in it that does say that `(void*) &array == (void*) &array[0]` must still be true (even though it has to be puzzled together from a couple of different sections). Otherwise something like `(*(&array))[0]` wouldn't work. – Some programmer dude Feb 21 '19 at 14:46
  • `*&a` is "noop" (for types without evil unary operator &), So your example is not the right one :/ . – Jarod42 Feb 21 '19 at 15:05
  • @Jarod42 While a compiler is allowed to optimize that noop, consider a naive non-optimizing compiler. Or how about the convoluted `void* p = &array; int (*a)[5] = (int(*)[5]) p; std::cout << (*a)[0];`? If `(void*) &array == (void*) &array[0]` is not true, then the dereference of `a` would not give the original array and the indexing of it would not be correct. – Some programmer dude Feb 21 '19 at 15:17
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/188828/discussion-between-jarod42-and-some-programmer-dude). – Jarod42 Feb 21 '19 at 15:27
  • How do you read `int(*)[5]` ? Pointer to array of 5 elements of type int ? – Sergiy Kolodyazhnyy Feb 22 '19 at 02:32
  • @Jarod42 Sorry I had went home. I also often need time to form my train of thoughts when writing, so that kind of makes me dislike chats. – Some programmer dude Feb 22 '19 at 06:49
  • i had the same question... what i can not get properly is the folllowing: lets say we have the int array[10]. array then is a pointer to the first element (&array[0]). Seems ok at first thought but if &array is &array[0] then that means that array[0] holds the address of the array (which it does not). How is that possible? Or is it that array word is not actually a pointer but when we write it is "substituted" as the address (and thus when we write &array we say the address of that address)? I'm sorry if i make syntactical mistakes , i hope i'm clear... Thanks in advance – Νίκος Αντωνετσής May 20 '23 at 18:21
  • @ΝίκοςΑντωνετσής Both `&array` and `&array[0]` points to the same location in memory, but they are different types. `&array` is a pointer to an "array of 10 `int` values", or `int (*)[10]`. While `&array[0]` is a "pointer to a single `int` element" of the array, with the type `int *`. It's the same with `&array[6]`, it's also a "pointer to a single `int` element" and also have the type `int *`. – Some programmer dude May 20 '23 at 18:37
  • @ΝίκοςΑντωνετσής Also consider something simple like `int var;`. When you apply the pointer-to operator `&var` you get a "pointer to a single `int` element", with the type `int *`, as well. – Some programmer dude May 20 '23 at 18:39
  • Maybe i miss something, thats why i'm stuck. The problem for me is that if array is a pointer, then &array is where this pointer is stored . And to my logic if array and &array have the same value we have a location in memory which contains its location. But this location should hold the first element of the array. – Νίκος Αντωνετσής May 20 '23 at 19:09
  • Also isn't it than when we write &array, we actually write &&array[0] ? – Νίκος Αντωνετσής May 20 '23 at 19:13
  • @ΝίκοςΑντωνετσής No. First because `&&` will be parsed as the logical AND operator. And secondly because the result of `&array[0]` is a *rvalue* and it's not possible to get a pointer to an rvalue. And thirdly, a pointer to the array, and a pointer to an element of that array, are *not* the same as a pointer to a pointer to an element. A pointer to the array is a pointer to the whole array as a single entity. – Some programmer dude May 20 '23 at 19:18
  • @ΝίκοςΑντωνετσής You say "if array is a pointer", and that's where your confusion is comming from. An array is an array and ***not*** a pointer. And a pointer is *not* an array. But an array can *decay* to a pointer (to its first element). So `array` on its own might be the array itself, as one single entity. Or if a pointer to a single element is expected then it decay to a pointer to its first element (`&array[0]`). But `array` itself is still the whole array. – Some programmer dude May 20 '23 at 19:23
  • Probably that's why... Well i was expecting an equivalence between: `int *hello= (int * ) malloc (40); hello=(int*)&hello;` and `int hi[10];` when using `hello` , `&hello` , `hello[0]` ,`&hello[0]` and `hi ` ,`&hi `, `hi[0]`, `&hi[0]` , which breaks when i do `hello[0] =1 ;` (but on the othe hand i can do `hi[0] =1;`) – Νίκος Αντωνετσής May 20 '23 at 19:46
  • 1
    @ΝίκοςΑντωνετσής The assignment `hello=(int*)&hello` is wrong. That you need a cast to silence the compiler should be a sign of that. – Some programmer dude May 20 '23 at 21:20
1

An array of X's has to behave like a pointer to a contiguous list of X's in memory much like a pointer. However, nowhere is it written where the memory that stores that data is must be it's own address and writablej. In the case of an explicit pointer there is a new allocation for this address (in this case the stack) however for an array, on the stack, the compiler already know where the contents are so no new allocation is needed.

As a consequence, its not safe to treat it as a pointer, without indexing. e.g.:

pArray = nullptr; // This is a memory leak, unless a copy is taken, but otherwise fine.
array = nullptr; // This is will make the compiler upset
ANone
  • 202
  • 1
  • 4