4

This problem is a follow up from Declaring array of int

Consider the following program:

#include <iostream>
#include <string>

int main()
{
  int x[10];
  std::cout << sizeof(x) << std::endl;
  int * y = new int [10];
  std::cout << sizeof(y) << std::endl;
  //delete [] y;
}

sizeof(x) prints 40 (total size), sizeof(y) prints 8 (pointer size)

It looks interesting, to me int x[10] is no different than y except it is located in the stack. Where does c++ actually stored the size of x? Does c++ get it from the stack? Or a fix sized array is treated as a struct with size internally?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
James Maa
  • 1,764
  • 10
  • 20
  • 2
    It doesn't store it at all. If you need that use a `std::array` instead. – user0042 Sep 22 '17 at 16:40
  • 4
    It doesn't (store the size), the compiler know the full type of `x` and that includes the size of the array. `y` is just a pointer (not an array) so that is all the compiler knows about it. Also note: `sizeof` is evaluated at compile time not a runtime. – Richard Critten Sep 22 '17 at 16:42
  • 2
    @user0042, Even `std::array` doesn't store the size. At least I'd expect implementations to not do that. – chris Sep 22 '17 at 16:43
  • 7
    In the case of a fixed size array, such as x[10] in the question, the compiler "stores" the size in the compiled code, such as sizeof(x) ends up as a constant of 40 in the compiled code, since as pointed out by Richard Critten, sizeof() is evaluated at compile time. – rcgldr Sep 22 '17 at 16:44
  • 2
    It's part of the type. A `int[10]` is a different type than an `int[8]`. The compiler knows this information so it can get it's size. – NathanOliver Sep 22 '17 at 16:46
  • @rcgldr Compile time operator looks solid to me, can you make it an answer? – James Maa Sep 22 '17 at 16:51

3 Answers3

4

The size of an array doesn't need to be stored, the compiler itself knows how big it is because it's part of the type.

When you dynamically allocate an array as you did with y in your example, the size of the array does need to be stored somewhere so that delete[] can do the right thing. But this is an implementation detail that isn't accessible to the program.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
3

You have two different types:

int x[10];

This declares a type of int[10]. As you can see, the size of the array is part of the type.

int * y;

This is a pointer to an int. It will have size equivalent to the size of a pointer on your system. Your system appears to have 64 bit pointers (commonplace now).


Here's a little trick you can do in C++17:

template<class T>
std::enable_if_t<std::is_pointer_v<T>> foo(T ptr)
{
    std::cout << "Called foo for a pointer type" << std::endl;
}

template<class T, int N>
void foo(T (&arr)[N])
{
    std::cout << "Called foo for an array type of size " << N << std::endl;
}

We defined two functions named foo. The first one uses type traits to only enable itself for pointer types, and the second one is for array types (by reference).

We can call them from main:

int x[10];
int * y = nullptr;
foo(x);
foo(y);

And get output that looks like this:

Called foo for an array type of size 10
Called foo for a pointer type

Runnable code


Edit: Mark Ransom gave a good aside about the size of the array allocated for y, and I'll throw in a little piece, too. While it is indeed an implementation detail, what's common is that the implementation of the memory allocator (like malloc or new) under the hood will write this value to the start of the memory block that it allocates. That way, when you call delete, you don't have to know how many bytes to delete; the deallocator (free or delete) can check the start of the memory block for how big it is. So an allocation for, say 1 byte, may actually allocate more than 1 byte. (Again, this is only one way it can be done)

Community
  • 1
  • 1
AndyG
  • 39,700
  • 8
  • 109
  • 143
2

The size of the array is evident in the compiled C++ code (the assembler code). It's equivalent to how sizeof() gets evaluate at compile time.

As a result, it doesn't store it, the compiler knows the size of the array.

When you dynamically allocate memory, the compiler again knows the size of the array and remembers it (it's implementation-defined where and how). As a result, when you call delete[], you don't need to specify the size of the array, the compiler knows.

gsamaras
  • 71,951
  • 46
  • 188
  • 305