How to get the size of an array in C++?
Ok, so for newbies, this is not exactly straight forward. While, C++ is not like other languages which have simple functions to get sizes of arrays, it does have replacements for arrays that are simple to use. The STL has a vector
, which is a linked list that acts like an array but has more user friendly options such as an easily accessible size value (and an easy way to add a value and re-size the vector if needed).
The first question is this: Why do you need to get the size of the array? An array is always created with a size. You can always store it.
Of course you are going to have a reason why you are doing this or you wouldn’t be searching this. However, some of you are going to realize you have the value already and use it, but others are still going to try to dynamically get the array size.
So YES, you can get an array size usually. There are certain ways to do it and certain things to avoid.
- An array cannot be created without using a constant size. So you should know it and so yes it is up to you to store the size.
- You cannot create a dynamic array, there is no such thing. You can create a pointer to a new array but you have to pass in a size, so if you are passing in a size, you can also store the size you pass in, right? Yes you can.
- Use a vector instead of an array.
Ok, you really want to try to get the size of an array without storing the size of the array yourself and without using a vector. Ok, we will give you some options but they have pitfalls, so know them and don’t fall in them.
There is a function called sizeof() that you should get to know. Here is a bit of code that will help you get to know the sizeof() function and how to use it to get array sizes. Load this into your favorite IDE and step through it or just compile and run it. Take time to read both the output and the comments in the code.
#include <iostream> #include <cstdlib> #include <ctime> #define MAX_SIZE 20 using namespace std; template <typename T, size_t arraySize > size_t sizeOfArray( T const (&a)[arraySize] ) { return arraySize; } int main() { // Static array. The value must be a constant value. int intArray1[10]; // You have statically written 10, so you know this array is size 10 cout << "intArray1 size is 10" << endl; cout << "sizeof(intArray1) = " << sizeof(intArray1) << " (Obviously not the way to get an array size.)" << endl; cout << "sizeof(intArray1)/sizeof(intArray1[0]) = " << sizeof(intArray1)/sizeof(intArray1[0]) << " (Appears to work in this instance.)" << endl << endl; // Static array. The value must be a constant value, since this used a defined value, // MAX_SIZE, you know the size. int intArray2[MAX_SIZE]; cout << "intArray2 size is " << MAX_SIZE << endl; cout << "sizeof(intArray2) = " << sizeof(intArray2) << " (Obviously not the way to get an array size.)" << endl; cout << "sizeof(intArray2)/sizeof(intArray2[0]) = " << sizeof(intArray2)/sizeof(intArray2[0]) << " (Appears to work in this instance.)" << endl << endl; // So what if I don't know the size, because it is dynamic? // Lets create a random number between 1 and 100. srand ( (int)time(NULL) ); int arraySize = rand() % 100; // You cannot use this as a static array size // int intArray3[arraySize]; <-- Compiler error: error C2057: expected constant expression // You can create a pointer to a new dynamicly sized array. But it is a pointer type not // an array[size]. T *t and T t[size] are different types. int * intPtrToArray = new int[arraySize]; cout << "intPtrToArray size is " << arraySize << endl; cout << "sizeof(intPtrToArray) = " << sizeof(intPtrToArray) << " (Obviously not the way to get an array size, it got the pointer size.)" << endl; cout << "sizeof(inArray2)/sizeof(intPtrToArray[0]) = " << sizeof(intPtrToArray)/sizeof(intPtrToArray[0]) << " (Hey this didn't work this time? Why?)" << endl << endl; cout << "sizeof(*inArray2)/sizeof(intPtrToArray[0]) = " << sizeof(*intPtrToArray)/sizeof(intPtrToArray[0]) << " (Trying do derefence the pointer still failed? Why?)" << endl << endl; // So how do you get the size you might ask? Well, you already know it. The size is the // value stored in the "arraySize" variable. You had to pass something in when you // declared the dynamic array, new int[something], so you store something. // So it looks like sizeof(myArray)/sizeof(myArray[0]) works as long as I don't use a // pointer. Is there a way to make the compiler check this for me? Yes, that is what // the handy function above is for. cout << "Using template function" << endl << endl; int size1 = sizeOfArray(intArray1); cout << "intArray1 size is 10" << endl; cout << "sizeOfArray(intArray1) = " << size1 << endl << endl; int size2 = sizeOfArray(intArray2); cout << "intArray2 size is " << MAX_SIZE << endl; cout << "sizeOfArray(intArray2) = " << size2 << endl << endl; // int size3 = sizeOfArray(intPtrToArray); <-- Compiler error: // error C2784: 'size_t sizeOfArray(const T (&)[arraySize])' : could not deduce template // argument for 'const T (&)[arraySize]' from 'int *' } [/sourcecode] Now you know how you can use the <code>sizeof(myArray)/sizeof(myArray[0])</code> statement. However, you also know that such a statement won't work when dealing with pointers to dynamic arrays. And let's face it you arrays are probably going to be dynamic most of the time. That means you should probably use a <code>vector</code> instead of an array. Ok, lets say you don't want to use a <code>vector</code> still. You want to use the <code>sizeof(myArray)/sizeof(myArray[0])</code> statement anyway. Well, then you should at least do it in a way that make the compiler complain if you accidentally use a pointer to an array instead of an array. Here is some code that will cause the compiler to complain if you pass a pointer to an array instead of passing an array. [sourcecode language="cpp"] #include <iostream> #include <cstdlib> #include <ctime> #define MAX_SIZE 20 using namespace std; template <typename T, size_t arraySize > size_t sizeOfArray( T const (&a)[arraySize] ) { return arraySize; } int main() { int intArray1[10]; int size1 = sizeOfArray(intArray1); cout << "intArray1 size is 10" << endl; cout << "sizeOfArray(intArray1) = " << size1 << endl << endl; int intArray2[MAX_SIZE]; int size2 = sizeOfArray(intArray2); cout << "intArray2 size is " << MAX_SIZE << endl; cout << "sizeOfArray(intArray2) = " << size2 << endl << endl; srand ( (int)time(NULL) ); int arraySize = rand() % 100; int * intPtrToArray = new int[arraySize]; // int size3 = sizeOfArray(intPtrToArray); <-- Compiler error: // error C2784: 'size_t sizeOfArray(const T (&)[arraySize])' : could not deduce template // argument for 'const T (&)[arraySize]' from 'int *' } [/sourcecode] So this template function will help you avoid one pitfall of accidentally passing in a pointer to an array instead of an array by making the compiler complain if you do it. However, I am sure this template has some pitfalls that you may encounter as well. Another gotcha is that passing an array in a function ends up being the equivalent of a pointer and so you cannot get the size: So if we added the following function to our code above we would get the same compiler error we see when passing a pointer. We don't even have to call the function in <code>main()</code>. [sourcecode language="cpp"] void passMeAnArray(int inIntArray[]) { int i = sizeOfArray(inIntArray); }
What is the problem? Well, even though we show the parameter passed to the function as int inIntArray[]
, it is really not an array, it is a pointer to an array and would be the same as writing int * inIntArray
.
Are there more gotchas? You bet there are. There is so much more to learn. All my arrays are of type int in this example. Here are some questions to make you think…
What happens with other types?
What happens when the array is an array of objects not types?
What happens when the objects contain multiple pointers?
What happens if the object using for an array inherits another object?
What happens if the object using for an array is created using multiple inheritance?
Wow, this is getting more complex than it has to be. Why didn’t you just use a vector
? See the code below to see how easy this is with a vector
.
#include
#include
#include
#include
using namespace std;
int main()
{
vector
cout << "intArray1 size is " << intArray1->size() << endl << endl;
// Create a random number between 1 and 100 and add that many random elements.
srand ( time(new time_t()) );
vector
for (int i = 0; i < (rand() % 1000); i++)
{
intArray2->push_back(rand() % 1000);
}
cout << "intArray2 size is " << intArray2->size() << endl << endl;
}
[/sourcecode]
I hope that you have been convinced to use a vector
and if not you are doing everything you can to avoid common pitfalls.