a tutorial on ‘dynamic’ arrays in C

Friday, February 1st, 2008 @ 8:12 am

For the purposes of education and the prospect of writing a new game, I’ve been doing some poking around in C. I’ve certainly learned a few things (and expect to learn more in the future) Prior to this, I’ve only had experience with C++, which some would argue is a completely different beast altogether. However, this post is not intended to discuss the differences between C and C++.

Anyways, I figured I might share a few snippets and wisdom that I’ve picked up along the way, so here’s a quick (?) rundown of how to use structs and pointers to create “dynamic” arrays that will resize as you need them.

Right, so let’s suppose you’ve got a struct built that you’ll use to hold some data…

typedef struct {
    char *name;
    int number;
} DATA;

And we’ll also need to set up an array, along with some variables to track how many items are in the array and how large the array is…

DATA    *TheArray;
int     numElements = 0; // keep track of the number of elements used
int     numAllocated = 0; // essentially how large the array is

What’s this? I’m not using []’s to define the size of the array? That’s right. At this point, the array is uninitialized and currently just a pointer. We’ll need to allocate memory for each entry into the array.

So next, we need a way to add items to our array that will be mindful of the fact that it is dynamic. What is needed is a function that will do three things:

  • Initialize the array if it is not already initialized.
  • Resize the array if more space is needed.
  • Add new items to the array.

Keeping that in mind, let’s take a look at the realloc function’s prototype:

void * realloc ( void * ptr, size_t size );

The purpose of this function is to re-allocate memory to a pointer that already has memory allocated to it. Of course, you’ll only want to use it to make memory allocations larger, otherwise you’ll risk losing data. The size parameter is the amount of memory that you want to allocate. And the other parameter, ptr, is where you’d like to allocate it to. In this case, it’ll be the TheArray pointer that we’ve defined above. What is great about realloc is that if the ptr is NULL, the function will act just like malloc. This will allow us to use this one call for both initializing and resizing the array. Check this realloc reference page for more information.

Here is the AddToArray function …

void AddToArray (DATA item)
{
    if(numElements == numAllocated) // need more refs?
    {
        if (numAllocated == 0)
            numAllocated = 3; // start off with 3 refs
        else
            numAllocated *= 2; // double the refs allocated

        TheArray = (DATA*)realloc(TheArray, (numAllocated * sizeof(DATA)));

        if (TheArray == NULL)
        {
            fprintf(stdout, "ERROR: Couldn't realloc memory!");
            exit(2);
        }
    }

    TheArray[numElements] = item;
    numElements++;

    return;
}

You can see that it performs all three requirements listed above.
You may ask, ‘why is the allocation size doubling each time a resize is needed?’. This is done mainly because realloc() can be an expensive call, and if you spend a lot of time resizing your array, it could slow down the execution of your application. This way, it’s only done once in a while. Of course, feel free to fiddle with the initial allocation as well.

Also, be careful when using realloc(), as you’ll need to remember to use the free() function later on to free the memory that you’ve allocated to your program. You’ll want to run this code when you’re done using the array …

// Deallocate!
free(TheArray);

I’ve got a little example available right here:

Download Example - (arrays.c - 1.78kb)

It compiles and runs just fine using GCC, but I haven’t tried it with anything else, so your mileage may vary. Also, a huge special thanks to DrPetter and X-0ut for their help on this subject!

As always, comments are welcome! :)

Game Dev, Misc


AddThis Social Bookmark Button

Leave a Reply