Bold Aesthetic Creative Games

An Indie Game Studio Developing Bold, Aesthetic & Creative Video Games

C++ Programming Series: Dynamic Arrays (Part 1)

C++ Programming Series: Dynamic Arrays (Part 1)

Before we get into the dynamic arrays, it is important to understand why we use them and when to use them.

Here’s the simplified concept of memory types.

The program that we execute stores and works with the data, information and variables (collectively called memory) in the RAM (Random Access Memory). Upon closing the program, it no longer remains there. The memory that remains saved even after a program is closed, is present in ROM (Read Only Memory). For example, the photos, text files and the program itself stored in the hard-drive.

Now, here’s the important bit. RAM is generally divided into two parts: Stack and Heap. The stack is the tiny amount of RAM that can be used by the program for quickly accessing the memory. When we make variables, the way we did in this series, we are saving this in it.

On the other hand, the heap is the remaining big chunk of RAM that can be used by the program to work on a large and uncertain amount of data.

The question that why this division exists? It is pretty straightforward. As the stack is much smaller than the heap, it is much faster to access the memory in the stack than in heap. But stack has its limits as it is tiny in size which means that it is not supposed to have an uncertain size of data and is not supposed to be holding onto something for an indefinite period of time. Here comes into action, heap. Heap is there for that purpose: the uncertain size of data and no time constraints.

There are multiple ways to store variables in heap. One of them is to simply define a variable above and outside the main function.

int iAmInHeap = 95;

int main()
{
    int iAmInStack = 5;

    return 0;
}

Functions outside the main function can be called global variables and they can be manipulated during execution from outside i.e they are not secure and it is not a good habit to make global variables.

At the ending curly bracket (i.e at the end of a block), the stack memory is destroyed and can not be used anymore. This is perhaps, what we call the scope of a variable. The very first post of this series might remind you what I meant here.

On the other hand, heap memory is destroyed only when you destroy it. But the variable it is stored in is no longer accessible after the end of a block.

Alright, I have said so much. Now, let us get into the practical heap situation. To make a typical heap variable (that is not a global variable), the following is the code.

int main()
{
    int* typicalHeapVar = new int;
    *typicalHeapVar = 10;

    delete typicalHeapVar;

    return 0;
}

Time to introduce a pair of keywords: new and delete. Before using dynamic arrays, always keep in mind that:

Where there is new, there is delete as well.

I have to use this kinda dramatic quote to remind myself of this very important thing. And that is because new allocates the memory and delete de-allocates the memory.

new without delete means memory leaks in the program. delete without new is not as bad because delete checks whether the pointer is NULL or not. So make a habit to set the pointer to NULL after deleting it.

But what about the practical heap situation? Let’s say that we are making a program that blurs all the images in a folder. All the images! That is what uncertain size of data means.

We know that when we make an array, we can not use a variable to set the size of an array. Sure that we can have a limit to it like what I did below.

const int MAX_IMAGES = 100; //That is the limit of our program!

//Suppose that Image is a user-defined structure.
Image images[MAX_IMAGES];

//We get the images from a folder with a function called getImagesFromFolder that gets all the images and saves them into the array of Image objects.
//It also returns the number of images present in that folder.
int noOfImages = getImagesFromFolder(images);

//Blur them all...
for(int i = 0; i < noOfImages; i++)
{
    //Suppose that... alright you get it already!
    blurImage(images[i]);
}

//Then, save them back...

You can point out 3 flaws with the program.

  • First one is that an image can be of any resolution and any size. The stack is used here to possibly store MB’s of image data. Not a good thing.
  • Second is again, the limit. What if the images are more than 100.
  • The third is the unnecessary use of memory. If the folder contains 10 images, there are still 90 useless array elements. It won’t affect the performance of the program but it will definitely shorten our already tiny stack.

Okay, maybe I am exaggerating. But it is to explain the benefits of using heap in such situations.

This is how it will look when we use dynamic arrays.

//No more limit variable

Image* images;

//First, we simply throw in a NULL pointer and get the total number of images in the folder.
int noOfImages = getImagesFromFolder(NULL);

//Then, we use this variable to tell us the number of elements our array will have.
images = new Image[noOfImages];

//Then. we get the images from the folder.
getImagesFromFolder(images);

//Blur them all...
for(int i = 0; i < noOfImages; i++)
{
    //Suppose that... alright you get it already!
    blurImage(images[i]);
}

//Then, save them back...

//WE MUST DESTROY WHAT IS CREATED...
delete[] images;

Now, you also know how to make dynamic arrays (not just typical heap variables).

My explanation may be inaccurate and could have faults so, I suggest you look around as well. As for the practical heap situation, I hope you got my point. The series is almost coming to an end.

Usually, people know all that. But they don’t know what is the right place to use them. I learned it the hard way. And I am still learning and prone to errors.

Leave a Reply

Your email address will not be published. Required fields are marked *