Reputation: 109397
This question was inspired by a similar question: 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)).
Upvotes: 64
Views: 72153
Reputation: 4626
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;
}
Upvotes: 3
Reputation: 39389
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.
Upvotes: 71
Reputation: 1
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
Upvotes: -1
Reputation: 9309
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().
Upvotes: 2
Reputation: 671
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.
Upvotes: 3
Reputation: 11
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.
Upvotes: -1
Reputation: 333
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[]
Upvotes: 0
Reputation: 36429
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.
Upvotes: 1
Reputation: 179779
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]);
Upvotes: 1
Reputation: 54554
@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[]
.
Upvotes: 0
Reputation: 54554
Is there any way to determine the size of a C++ array programmatically? And if not, why?
Upvotes: 0
Reputation: 778
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.
Upvotes: 0
Reputation: 2305
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.
Upvotes: 20
Reputation: 186
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.
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.
Upvotes: 4
Reputation: 255
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.
Upvotes: 2
Reputation: 111856
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.
Upvotes: 2
Reputation: 121294
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.
Upvotes: 1
Reputation: 103485
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.
Upvotes: 19
Reputation: 3274
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
Upvotes: 2
Reputation: 65599
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);
}
Upvotes: 5