Introduction
In the previous tutorial, we discussed pointers. Pointers are a way to store the address of a value in memory. We then used this to pass a value to a function by reference, so that we could modify it within the function.
In this tutorial, we are going to extend our knowledge of pointers by talking about dynamic arrays. By dynamic, we mean that the length of the array is not known at compile time. In most applications, not knowing the size of the array at compile time is the norm, so this is a very important skill to master.
Code
So, let’s jump right in with an example of a dynamic array:
int length;
cin >> length;
int* vector = new int[length];
So, the first part should be familiar by now, we read in an int from the user. The second part declares an array of that length. The new keyword tells the computer to allocate space to store some information and return a pointer to that location. The computer will allocate sizeof(int)*length bytes. When the memory is allocated, it will be sequential, so if the user picked a length of 3, it would look something like this:
Address 1000 | Address 1004 | Address 1008 | Address 1012 | Address 1016 |
<other stuff> | 25 | 12 | 78 | <other stuff> |
Since an int is 4 bytes (32 bits). The other thing to notice is that the data stored in the array is random. This is because it hasn’t been set to anything, so it takes the value of whatever was there before. This is a common pitfall; do not count on the data in the array to be set to zero!
If you want the data to be set to zero, there are two ways to go about this. The first way is to put open and close parenthesis after the closing square brace:
int* vector = new int[length]();
The other way is to write a for loop to set every element in the array to zero (or any other value):
int* vector = new int[length];
for(int i = 0; i < length; i++)
{
vector[i] = 0;
}
This piece of code shows how to access the data within array using square braces []. This works the same way that it does with static arrays. Remember that the first element in the array has the index of zero.
Whenever you allocate an array with new, you must remember to delete the array when you are done with it!
delete[] vector;
This is extremely important, because forgetting to do this will lead to memory leaks. Memory leaks are when space is allocated in memory but is never cleaned up. The computer keeps track of all of the memory that a program is using so that no one overwrites data that that it is using. So, if the memory is no longer being used and never cleaned up, then no one can use it. If this goes on long enough, it will cause programs to crash, since there is no memory left for anyone to use.
Unfortunately, when to free memory isn’t always clear. How do I know that no one else is using it anymore? Well, that can be a tough question to answer. One way to make this question easier to answer is by sticking to a rule that whoever allocates the memory is responsible for deleting it. This means that if you wanted to write a function that fills an array with random numbers between 1 and 10, that the following example:
int* RandArray(int length)
{
int* vector = new int[length];
for(int i = 0; i < length; i++)
{
vector[i] = (rand() % 10) + 1;
}
return vector;
}
Would be a bad idea. This is because the RandArray function declares an array using the new keyword, but it can’t clean it up because it has to pass it back to the caller. So, it can’t clean up the memory that it allocated. A much better idea would be to declare the array outside of the function and pass it in:
void RandArray(int* vector, int length)
{
for(int i = 0; i < length; i++)
{
vector[i] = (rand() % 10) + 1;
}
}
int main()
{
int length;
cin >> length;
int* vector = new int[length]();
RandArray(vector, length);
for(int i = 0; i < length; i++)
{
cout << vector[i] << endl;
}
delete[] vector;
return 0;
}
Now, the person that creates the array has a chance to clean up the array and doesn’t have to rely on the caller knowing that it should clean up the array when it is done with it.
Summary
In this tutorial, we learned about how to allocate and use dynamic arrays. We also talked about the importance of cleaning up memory that is allocated and a strategy to help make that easier to manage.
In the next tutorial, we will be talking about lists. With dynamic arrays, you need to know the size of the array before it is created. This might not always be the case. What if you were searching through a text document and wanted to store every word that started with the letter a. In this case, there is no way to know how many words you are going to find. Lists allow for an efficient way to dynamically add and remove elements.
If you have any questions or comments about what was covered here, post them to the comments. I watch them closely and will respond and try to help you out.