Where does c++ store the size of fix sized array?

Viewed 808

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?

3 Answers

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.

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)

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.

Related