C Tutorial, Part IV


Dynamically allocated Memory


Compile-time 2-D arrays of char vs. dynamic (run-time) arrays of pointers

In part 3 of the tutorial (which was for self-study), we stored our dictionary in a 2-dimensional array of chars similar to:

#define MAX_WORDS 10
#define MAX_WORD_LEN 30
int main()
{
    char wordArray[MAX_WORDS][MAX_WORD_LEN];
    /* assume only 5 words
    ("horses", "cats", "rats", "dogs", "bats")
    were read into the array
    */
    return 0;
}

The memory allocated for wordArray looked like this:  (the Ø symbol is the null character or '\0')

                0    1    2    3    4    5    6    7    8    9    0    1    2    3    4
wordArray[0]: ['h']['o']['r']['s']['e']['s'][ Ø ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ]
wordArray[1]: ['c']['a']['t']['s'][ Ø ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ]
wordArray[2]: ['r']['a']['t']['s'][ Ø ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ]
wordArray[3]: ['d']['o']['g']['s'][ Ø ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ]
wordArray[4]: ['b']['a']['t']['s'][ Ø ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ]
wordArray[5]: [ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ]
wordArray[6]: [ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ]
wordArray[7]: [ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ]
wordArray[8]: [ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ]
wordArray[9]: [ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ][ ? ]

The disadvantages of the 2-D array of char are

  1. The amount of space allocated for each word is always MAX_WORD_LEN while the average word's actual length is likely much less. Thus, most of the storage is wasted.
  2. The number of rows in the array must be a compile-time constant. Thus,

A compile-time array of pointers solves disadvantage #1 but not #2

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_WORDS 10


int main(int argc, char *argv[])
{
    char *wordArray[MAX_WORDS];

    return 0;
}

The memory allocated for wordArray now looks like this

wordArray[  0      1      2      3      4      5      6      7      8      9  ]
          char*  char*  char*  char*  char*  char*  char*  char*  char*  char*
            |      |      |      |      |
        "horses"   |      |      |      |
                 "cats"   |      |    "bats"
                       "rats"    |
                               "dogs"

The disadvantage still remains that the number of pointers allocated is a compile time constant that may be much smaller or larger than the actual size of the input. So, like before,


The dynamic array of pointers solves both disadvantages!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_WORD_LEN 30

int main(int argc, char *argv[])
{
	char word[MAX_WORDLEN];  /* no getting around this! */
	char **wordArray;  /* pointer to char* - we will malloc an array of
	char*'s to this ptr at runtime */ 

	return 0;
}

The advantage to the dynamic array is obvious. We can allocate it at runtime choosing a reasonable number of initial words. If we assume an input file as follows:

horses
cats
rats
dogs
bats

The memory allocated for wordArray now looks like this

wordArray[  0      1      2      3      4  ]
          char*  char*  char*  char*  char*
            |      |      |      |      |
        "horses"   |      |      |      |
                 "cats"   |      |   "bats"
                       "rats"    |
                               "dogs"

Answers to Questions:

  1. No, because the run-time environment will clean that sort of stuff up. You definitely should free any run-time allocated memory that you're no longer using, though, while the program is running.

  2. If we delete the array of pointers first, the variable wordArray becomes stale and we need it to access the individual pointers in the array. So, doing it in reverse causes you to reference stale memory when you try to free the strings. Dynamic data structures must be freed from the inside out!