Determine the size of a C++ array programmatically?

C++ArraysPointersMemory Management

C++ Problem Overview


This question was inspired by a similar question: https://stackoverflow.com/questions/197675/how-does-delete-know-the-size-of-the-operand-array">How does delete[] “know” the size of the operand array?

My question is a little different: Is there any way to determine the size of a C++ array programmatically? And if not, why? Every function I've seen that takes an array also requires an integer parameter to give it the size. But as the linked question pointed out, delete[] must know the size of the memory to be deallocated.

Consider this C++ code:

int* arr = new int[256];
printf("Size of arr: %d\n", sizeof(arr));

This prints "Size of arr: 4", which is just the size of the pointer. It would be nice to have some function which prints 256, but I don't think one exists in C++. (Again, part of the question is why it doesn't exist.)

Clarification: I know that if I declared the array on the stack instead of the heap (i.e. "int arr[256];") that the sizeof operator would return 1024 (array length * sizeof(int)).

C++ Solutions


Solution 1 - C++

delete [] does know the size that was allocated. However, that knowledge resides in the runtime or in the operating system's memory manager, meaning that it is not available to the compiler during compilation. And sizeof() is not a real function, it is actually evaluated to a constant by the compiler, which is something it cannot do for dynamically allocated arrays, whose size is not known during compilation.

Also, consider this example:


int *arr = new int[256];
int *p = &arr[100];
printf("Size: %d\n", sizeof(p));

How would the compiler know what the size of p is? The root of the problem is that arrays in C and C++ are not first-class objects. They decay to pointers, and there is no way for the compiler or the program itself to know whether a pointer points to the beginning of a chunk of memory allocated by new, or to a single object, or to some place in the middle of a chunk of memory allocated by new.

One reason for this is that C and C++ leave memory management to the programmer and to the operating system, which is also why they do not have garbage collection. Implementation of new and delete is not part of the C++ standard, because C++ is meant to be used on a variety of platforms, which may manage their memory in very different ways. It may be possible to let C++ keep track of all the allocated arrays and their sizes if you are writing a word processor for a windows box running on the latest Intel CPU, but it may be completely infeasible when you are writing an embedded system running on a DSP.

Solution 2 - C++

Well there is actually a way to determine the size, but it's not "safe" and will be diferent from compiler to compiler.... so it shouldn't be used at all.

When you do: int* arr = new int[256];

The 256 is irrelevant you will be given 256*sizeof(int) assuming for this case 1024, this value will be stored probably at ( arr - 4 )

So to give you the number of "items"

int* p_iToSize = arr - 4;

printf("Number of items %d", *p_iToSize / sizeof(int));

For every malloc, new, whatever before the continuos memory block that you receive, there is also allocated a space reserved with some information regarding the block of memory you were given.

Solution 3 - C++

No, there is no way to do that in Standard C++.

There is no really good reason why not that I'm aware of. Probably, the size was considered an implementation detail, and best not exposed. Note that when you say malloc(1000), there is no guarantee that the block returned is 1000 bytes --- only that it's at least 1000 bytes. Most likely it's about 1020 (1K minus 4 bytes for overhead). In that case, the "1020" size is the important one for the run-time library to remember. And of course, that would change between implementations.

Which is why the Standards committee added std:vector<>, which does keep track of it exact size.

Solution 4 - C++

Common way to handle this is to either use a vector

int main()
{
   std::vector<int> v(256);
   printf("size of v is %i capacity is %i\n", sizeof(int) * v.size(), sizeof(int) * v.capacity());
}

or predefine the size

const int arrSize = 256;
int main()
{
    int array[arrSize];
    printf("Size of array is %i", sizeof(int) * arrSize);
}

Solution 5 - C++

C++ decided to add new to do a typesafe malloc, than new must know both size e numbers of elements for calling ctors, so delete for calling dtors. In the early days you have to actually pass to delete the numbers a objects you passed to new.

string* p = new string[5];
delete[5] p;

However they thought that if use new<type>[] the overhead of a number was small. So they decided that new[n] must remember n and pass it to delete. There are three main ways to implement it.

  1. keep a hash-table of pointer to size
  2. wrote it directly near the vector
  3. do something completely different

Maybe is possible to obtain the size like that:

size_t* p = new size_t[10];
cout << p[-1] << endl;
// Or
cout << p[11] << endl;

Or hell none of those.

Solution 6 - C++

Depending on your application, you could create a "sentinel value" at the end of your array.

The sentinel value must have some unique property.

You can then either process the array (or do a linear search) for the sentinel value, counting as you go. Once you reach the sentinel value, you have your array count.

For a simple C string, the terminating \0 is an example of a sentinel value.

Solution 7 - C++

Some magic:

template <typename T, size_t S>
inline
size_t array_size(const T (&v)[S]) 
{ 
    return S; 
}

And this is how we do it in C++11:

template<typename T, size_t S>
constexpr 
auto array_size(const T (&)[S]) -> size_t
{ 
    return S; 
}

Solution 8 - C++

That's because your variable arr is only a pointer. It holds the address of a particular location in memory, without knowing anything about it. You declare it to be int*, which gives the compiler some indication of what to do when you increment the pointer. Other than that, you could be pointing into the beginning or the end of the array or into the stack or into invalid memory. But I agree with you, not being able to call sizeof is very annoying :)

QuantumPete

Solution 9 - C++

There is no portable way of determining the size of a dynamically-allocated array in C++ given only its pointer. C++ is made to be very flexible and to give power to the user. For example, the standard does not define how memory allocators must work, e.g. by adding a required size header. Not requiring a header allows for a lot more flexibility.

As one example, consider a string implemented as a char * array. It's common to use pointers into the middle of the array to pick out substrings. As an example, see the strtok function in the standard C library. If some header were required to be embedded just before each array, you'd need to trash portions of the array before the substring.

An alternative way to handle the headers would be to have array headers in one block of memory and have them point to the raw array memory elsewhere. In many situations, this would require two pointer lookups for each reference, which would be a big drag on performance. There are ways of overcoming these deficiencies, but they add complexity and reduce implementation flexibility.

The std::vector template is my favorite way of keeping the size of an array bound to the array itself.

C is portable assembly language with a better syntax.

Solution 10 - C++

Now there is std::array, an efficient compile-time wrapper around a constant-size array:

#include <array>

int main (int argc, char** argv)
{
    std::array<int, 256> arr;
    printf("Size of arr: %ld\n", arr.size());
}

The parameters are <type, #elements>.

You also get a few other niceties, like iterators, empty(), and max_size().

Solution 11 - C++

No, there isn't any way to do this, you have to keep track of how big it is externally. Classes like std::vector do this for you.

Solution 12 - C++

You can't, fundamentally:

void foo(int* arr);

int arr[100] = {0};

foo(arr+1); // Calls foo with a pointer to 100-1 elements.

A C++ array is nothing more than a collection of objects which are stored in a contiguous memory region. Since there are no holes betweeen them (padding is inside objects), you can find the next element of an array by simply incerementing the pointer. At CPU level, this is a simple adjustment. C++ only inserts a sizeof(element) multiplier.

Note that implementations may choose to implement "fat pointers" which contain array bounds. They'd need to be twice as big, as you'd need to link to some kind of "array bound descriptor". As a side effect, on such implementations you could be able to call delete [] (1+new int[5]);

Solution 13 - C++

Unfortunately, this is not possible. In C and C++, it is the responsibility of the programmer to remember of the length of an array since array length is not stored anywhere. Delete[] and free() does remember the size of the allocated block but they might allocate more memory than requested so their internal data structures storing the sizes of allocated memory blocks might not give you the exact size of the your array.

Note that C++ STL vectors, which are basically arrays wrapped in a class with some helper functions, do store the length of the array so if you really need this functionality, you could just use vectors.

Solution 14 - C++

In general, no. Arrays in C and C++ are just blocks of memory with no bookkeeping information attached. Without storing the length of the array in memory, and adding overhead to do so, it is impossible in the general case.

There is an exception for arrays that are statically allocated. For instance, if you declare: int a[50] then sizeof(a) will work. This is possible because the [50] is part of the static type of the array: it is known to the compiler. sizeof is interpreted at compile time.

However, if you create a pointer: int *p = a, then sizeof(p) will return the size of the pointer as you mention, not the size of the array, because the compiler does not know what p points to.

Solution 15 - C++

> Is there any way to determine the size of a C++ array programmatically? And if not, why?

  1. No, unless you keep track of it yourself.
  2. Because if the compiler doesn't have to tell anyone besides itself about that information it constrains the compiler less. Whether that is desirable or not is up to debate.

Solution 16 - C++

@Dima,

> How would the compiler know what the size of p is?

The compiler has to know the size of p; otherwise, it cannot implement delete[]. The compiler doesn't need to tell anyone else how it figures that out.

For a fun way to verify this, compare the pointer returned by operator new[] to the pointer returned by new[].

Solution 17 - C++

The compiler can't know that

char *ar = new char[100] 

is an array of 100 characters because it doesn't create an actual array in memory it just creates a pointer to 100 uninitialized bytes in memory.

If you want to know the size of the given array just use std::vector. std::vector is a better array simply.

Solution 18 - C++

When you create array pointers (Create wrapper with template to pointers) you can't but when you create array of object, You can get the size of the array like that:

char* chars=new char[100];
printf("%d",*((int*)chars-1));

The delete[] function need to deconstruct all the objects in it. to do it the new[] keyword puts the number of elements behind all of the array.

The body of array is like that:

int count;
ObjectType* data; //This value is returned when using new[]

Solution 19 - C++

the way I do that is by dividing the size of the array by the size of the first element

int intarray[100];
printf ("Size of the array %d\n", (sizeof(intarray) / sizeof(intarray[0]));

It prints 100

Solution 20 - C++

You could just create an extra element of the array and then apply the most unlikely number that will be stored in the array. Then you can determine the number of elements through some function by passing that number.

In the case of declaring and initializing an array at the moment of creation, you can then scan it and then generate a number that does not match any of the elements of the array. But if you then modify one of the elements, you will not know if that element stores the same value as the last element, so you will then have to generate a new number to store in the last element.. Going through all that, you might as well just store the total number of elements at the moment of creation in a variable. And that will probably be the case if you only use the array within a function.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKipView Question on Stackoverflow
Solution 1 - C++DimaView Answer on Stackoverflow
Solution 2 - C++João AugustoView Answer on Stackoverflow
Solution 3 - C++James CurranView Answer on Stackoverflow
Solution 4 - C++Doug T.View Answer on Stackoverflow
Solution 5 - C++MykelykView Answer on Stackoverflow
Solution 6 - C++bearvarineView Answer on Stackoverflow
Solution 7 - C++ZingamView Answer on Stackoverflow
Solution 8 - C++Peter KühneView Answer on Stackoverflow
Solution 9 - C++Mr FoozView Answer on Stackoverflow
Solution 10 - C++Brent FaustView Answer on Stackoverflow
Solution 11 - C++Greg RogersView Answer on Stackoverflow
Solution 12 - C++MSaltersView Answer on Stackoverflow
Solution 13 - C++Tamas CzinegeView Answer on Stackoverflow
Solution 14 - C++James RoseView Answer on Stackoverflow
Solution 15 - C++MSNView Answer on Stackoverflow
Solution 16 - C++MSNView Answer on Stackoverflow
Solution 17 - C++SMeyersView Answer on Stackoverflow
Solution 18 - C++MessyCodeView Answer on Stackoverflow
Solution 19 - C++user4443767View Answer on Stackoverflow
Solution 20 - C++PERView Answer on Stackoverflow