0

Recently, I realized that if I create an array on the stack, then the following values ​​will be equal to it:

  • the address of the variable itself on the stack

  • the value of this variable (i.e. the same pointer)

  • the address of the first element of this array

It turns out that when I create an array of type T and size N, an area of ​​sizeof(T)*N bytes appears on the stack. For the code below, all three addresses will be the same:

#include <bits/stdc++.h>

using namespace std;

int main() {

    int automaticArray[5] {1, 2, 3, 4, 5};

    cout << "Variable value = " << automaticArray << ", variable adress = " << &automaticArray << ", first element addres = " << &automaticArray[0] << endl;
}

If I do the same with an array in a dynamic memory area, it will not be correct. The address of the variable itself (the one that will be on the stack) will differ from the two remaining values.

This is logical, because I store only the pointer on the stack, and 8 bytes are allocated for it. The array itself is located somewhere on the heap. For the example below, the addresses will not be the same:

#include <bits/stdc++.h>

using namespace std;

int main() {

    int* dynamicArray = new int[5] {0};

    cout << "Variable value = " << dynamicArray << ", variable adress = " << &dynamicArray << ", first element addres = " << &dynamicArray[0] << endl;
}

How is it possible that when creating an array on the stack (consider an example for ints), the first eight bytes will simultaneously contain a pointer to the array (i.e. a pointer to this variable itself), and the first 2 elements from array?

My guess is that the value of the variable (the address of the first element of the array) is not stored anywhere.

I checked this through GodBolt, but I'm not good at assembly, and I'm not 100% sure that my guess is correct.

image

9
  • You've just discovered one of C++ deeply held secrets: there is no such thing as an "array" in C++. It's a myth. A legend. An array is an artificial entity. A pointer, such as a dynamicArray is a real, breathing, living thing. What you're seeing is the difference between the two. In the case of a "real" (double air-quotes) array, there is no other option except to get the same memory address for a "real" (double air-quotes) array, since there's nothing else out there. But in case of a pointer you have different things: the pointer, and what it points to. Commented Jan 8, 2024 at 18:39
  • 5
    Side notes, it looks like you're learning C++ from a source that needs some updating. <bits/stdc++.h> is not standard C++ and should not be used., using namespace std; is not recommended. And new/delete should hardly every be used in modern C++. Use std::array for fixed size arrays (that at least behaves like an object), std::vector<int> for dynamically allocated (and resizable) arrays. And if you ever need to allocate memory yourself use std::make_unique (not new). Commented Jan 8, 2024 at 18:41
  • automaticArray is an array while dynamicArray is a pointer, a pointer to first element of an array, not an array. Arrays can decay to pointers to first element but that doesnt mean that arrays are pointers or vice versa Commented Jan 8, 2024 at 18:41
  • 2
    "...the first eight bytes will simultaneously contain a pointer to the array (i.e. a pointer to this variable itself) and the first 2 elements from array?" they do not. You need to read about array to pointer decay: stackoverflow.com/questions/1461432/… Commented Jan 8, 2024 at 18:43
  • generally its a good idea to experiment, but unfortunately generally there is a limit to what you can learn about c++ by experimenting. Mainly due to undefined/unspecified/etc behavior the output of some code example can be very misleading. Commented Jan 8, 2024 at 18:45

3 Answers 3

1

how is it possible that when creating an array on the stack we (consider an example for ints) in the first eight bytes will simultaneously contain a pointer to the array (i.e. a pointer to this variable itself) and the first 2 elements from array?

It is not possible. You are misinterpreting your output. In most cases where a subexpression of array type appears in an expression, it is automatically converted to a pointer to the first array element. This is a special exception to the usual rule for lvalue conversion, with the result that

cout << "Variable value = " << automaticArray

does not, in fact, print the contents of the array. It is 100% equivalent to

cout << "Variable value = " << &automaticArray[0]

. This behavior was inherited from C at the birth of C++, and has remained unchanged since then.

My guess is that the value of the variable (the address of the first element of the array) is not stored anywhere.

Be careful. Arrays and pointers are not at all the same thing. The address of the array indeed is not stored in memory in any accessible form. But the value of the array is an aggregate composed of the values of its elements, and that certainly is stored in memory.

Sign up to request clarification or add additional context in comments.

13 Comments

By “array value” I meant what will happen when casting it to a pointer. Those. not the array elements themselves, but a pointer to the first of them.
But how can this be, because in order to get &automaticArray[0] we must do &*(automaticArray +0). Those. again you need to know exactly the value of automaticArray
@BychkovArthur, the value of an array is the contents of the memory it occupies, interpreted according to the array type. That's what "value" means in this context. And for an array, that is a composite of the values of the array elements. I'm uncertain what you mean by casting to a pointer, you not having presented an example, but note well that expressions such as static_cast<int *>(automaticArray) and (int *) automaticArray are among those where array-to-pointer conversion is automatically performed, so the casts are pointer-to-pointer conversions, not array-to-pointer conversions.
@BychkovArthur, how can that not be? Again, the lvalue automaticArray is automatically converted to a pointer when evaluated (with a very few exceptions). The indexing operator is an operator on pointers, not on arrays, and you correctly observe that automaticArray[0] is equivalent to *(automaticArray + 0), and therefore that the address-of operator has the same effect on each. But &* composes to the identity operation, as does + 0, so that boils down exactly to &automaticArray[0] == automaticArray. But only because of the automatic conversions involved.
@BychkovArthur, yes, the compiler does need to know the address of the array. But it does not need to store that address in memory in order to know it. Not any more than it needs to store the address of an int, though it needs to know that, too, to be able to read and write it.
|
0

In C++ use std::array and std::vector. Do not get hung up on pointers to arrays if you don't have to. If you ever need a pointer you can use .data() method on both std::array, and std::vector

#include <array>
#include <vector>

// you cannot return "C" style (stack) arrays
// but you can return std::array
std::array<int,4> make_array()
{
    std::array<int,4> values{1,2,3,4};
    return values;
}

int main()
{
    std::array<int,4> array1 = make_array(); // Allocated on the stack

    std::array<int,4> array2{2,3,4,5}; // Also allocated on the stack    

    std::vector<int> vector{1,2,3,4}; // Allocatd (for you) on the heap;

    // when vector goes out of scope memory is deallocated for you
}

3 Comments

I do this for educational purposes. It is clear that there is a vector and an array. But my question was, where is the value of this pointer stored?
@BychkovArthur • automaticArray is not a pointer, it's an array. There is no "pointer" to be stored. An array will decay into a pointer to the first element, as a C-style affordance (which C++ does as well, to be backwards compatible with C).
And the "bad" thing about pointer decay is that you will loose all size information of the array and it is the main reason I avoid "C" style arrays altogether (leads to all kinds of unsafe code and out of bound bugs).
0

The difference is that dynamicArray is a pointer, while automaticArray is an array.

The easier case is dynamicArray. new int[5] {0}; allocates an array and returns a pointer to its first element. In memory you have

 ----------------             
 | dynamicArray |   ------
 ----------------        |
                         |
                         v
                        -------------
                        | 0 1 2 3 4 |
                        -------------    

That is, you have a pointer to int. Its value is the address of the first element of the newly allocated array. Hence &dynamicArray[0] == dynamicArray. The address of that pointer however, is some other remote address, because the pointer is stored separate from the actual array.

Whith automaticArray things are different. In memory you only have

                        -------------
                        | 0 1 2 3 4 |
                        -------------    

And thats it. What you are missing is array to pointer decay. In this line

cout << automaticArray << &automaticArray << &automaticArray[0] << endl;

All three addresses are the same, because automaticArray does decay to a pointer when passed to std::ostream::operator<<. That is because there is no overload that would take a reference to an array of 5 integers. You could write one yourself. For illustration, consider this:

#include <iostream>


std::ostream& operator<<(std::ostream& out, int (&arr)[5]) {
    for (int i=0;i<5;++i) out << arr[i] << " ";
    return out;
}


int main() {

    int automaticArray[5] {1, 2, 3, 4, 5};
    std::cout << automaticArray;
}

Which outputs:

1 2 3 4 5 

You wouldn't actually write code like this, but its only to demonstrate that automaticArray is not a pointer. Its an array. It potentially does decay to a pointer to the first element of the array. And thats what happens in your code, because there is no << overload that takes a reference to array. But if you pass the array via reference then no to-pointer decay happens. In the above example automaticArray is an array and arr is a reference to that array. No pointers are involved.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.