Dynamic Memory Allocation in C

When building your C programs whenever a variable is defined the compiler automatically allocates the correct amount of memory that is needed for that variable based on the data type. If your program is taking data from a file and storing it to an array in memory there is three options that you have to be able to do this correctly. The first we talked about in a previous blog shortly and it is simply defining the array with the maximum number of possible elements that it can have.

This means that the array can not contain more than the 100 elements that were allocated for it. If it is larger than the 100 then the program won’t work, or you would have to go back to your program and change the size to be larger and then recompile the program again. This will always have a chance of running into the same problem later on in the future as the data for the array might dynamically grow. The second option you have is to use a variable-length array to dimension the size of the array at the runtime. The third way to be able to do it is to allocate the array dynamically using the memory allocation routines provided by C. Using these dynamic allocation functions, allows you to get the correct amount of storage that you need. Dynamic memory allocation is only possible because pointers are available. A majority of production programs will use dynamic memory allocation, it also allows you to create the pointers at runtime that are the right size needed for the data.

Within the C library there are four functions that are used for Dynamic Memory Allocation.

  • malloc()
  • calloc()
  • free()
  • realloc()

These functions can all be used by including the <stdlib.h> header file. Let’s take a closer look at each one of these functions that are provided for us and how they work. The simplest function in the C library that allocates memory at runtime is malloc() . This function takes one argument and it is simply the number of bytes of memory that you want allocated. malloc() returns the address of the first byte that was allocated and for that reason we need to have a pointer a be able to store that address. This is a simple example of how to use the malloc() function:

This sets 100 bytes of memory and it’s assigned the address of this memory block location to the pointer pointerNumber . This sets up so that 25 int values can be store because a data type int requires 4 bytes of memory. Instead of assuming the size of the data type, it would be better to remove the assumption and instead the program will allocate space for 25 values of type int.

This allocates enough memory to accommodate 25 values of the data type passed to the sizeof() function. If the memory that you have requested can’t be allocated for any reason the malloc() function returns a pointer that has a value of NULL . This is a good way to test that your memory is being stored before continuing with the rest of the program.

The function that is close to malloc() is the calloc() function which is similar but offers a couple of advantages of malloc() . The calloc() function allocates the specified number of blocks of memory for the specified type. The calloc() function takes two arguments, the first argument is the number of data items that need to have space allocated for them. The second argument is the size of each data item that will be allocated. The syntax for calloc() is similar to malloc() it looks like this:

This function will also return a NULL pointer if it is not possible to allocate the necessary amount of memory. The main advantage to calloc() over malloc() is that calloc() will initialize the memory that is being allocated so that all the bytes are zero.

The other function that is used to allocate memory is the realloc() function, this function lets you reuse or extend memory that you have already previously allocated using malloc() or calloc() . The realloc() function also takes in two arguments, the first argument being the pointer that was previously returned by either malloc() or calloc() and the second argument the size in bytes of new memory that you want to have allocated. This function transfers the contents of the previous allocated memory to the newly allocated memory that was created. The realloc() function returns a void* pointer or NULL if the the function fails for any reason. The huge importance of this function is that it preserves the contents of the previous memory area.

With this example first we pass the pointer as the first argument and then the second argument of the function is the size we want to have added, which in this case is another 25 values of size int .

The final function we are going to look at when dynamically allocating memory is the free() function. This function is very important, because whenever you allocate memory you need to release that memory when it is no longer needed. It is always better to explicitly release the memory even if it is just at the end before you exit the program. To be able to release or to “free” up the memory allocated you need to still have access to the address that references the memory. Then you just need to use the free() function which takes one argument, and that argument is the pointer that is holding the address of the allocated memory. The syntax for it is simple :

When working with dynamic memory allocation is always good to remember that it is always better to allocated fewer larger blocks of memory as opposed to many small blocks of memory. Only keep the memory stored for as long as it is needed and make sure to release it when it is done being used. If you dynamically allocate memory for your program it is less likely that your program will run into errors or that your program will run out of allocated space.

Full stack web developer with experience in Ruby on Rails, JavaScript, React and Redux and learning more!