Introduction to Dynamic Memory Allocation

By: Jerrett Longworth, Idel Martinez

What exactly is **dynamic** memory?

When we use memory in our computers, memory is stored in a few different places depending on the situation. Generally, this involves a stack and a heap. This is a representation of how a program stores data in memory:

+--------------------------+
|       machine code       |
+--------------------------+
|         globals          |
+--------------------------+
|           heap           |
|            ↓             |
|                          |
|                          |
|                          |
|                          |
|                          |
|                          |
|            ↑             |
|          stack           |
+--------------------------+

These two locations in memory operate based on two types of memory allocation: static allocation and dynamic allocation.

+--------------------------+
|       machine code       |
+--------------------------+
|         globals          |
+--------------------------+
|           heap           |    <------- Dynamically allocated
|            ↓             |
|                          |
|                          |
|                          |
|                          |
|                          |
|                          |
|            ↑             |
|          stack           |    <------- Statically allocated
+--------------------------+

Fun fact: If too much memory is allocated on the stack, it will “overflow” into the heap. This causes what is known as a “stack overflow.” (Not to be confused with the website.)

In the end, the biggest difference between static and dynamic memory is scope.

In static memory, data sticks around within the “curly braces” it was created in. Once either a function ends, a loop completes, or the program terminates, the static memory associated with that scope is returned to be used for other programs.

For example, the integer n in this small program will only exist in funny_function(), and that information is lost when the function ends:

#include <stdio.h>

void funny_function(void)
{
  int n = 6;
  printf("The value of n is %d!\n", n);
}

int main(void)
{
  funny_function();
  printf("I can't see the value of n in main()...\n");

  return 0;
}

In dynamic memory, data sticks around as long as you want. You can allocate memory and use it at any time, in any function, free-of-charge. You now have full control of where in your program a piece of memory can be used.


Introducing Dynamic Memory Allocation

In C, we have a few functions available in the stdlib.h library, one of the most important being malloc() (short for memory allocation).

So how do I use this malloc() thing?

malloc() takes one parameter: The amount of memory (in bytes) you would like to allocate.

What if I don’t know how many bytes I need? Can I put in a random number? No. You must always decide how much memory you want to allocate.

Example:

// Allocate the memory needed to store 100 integers.
malloc(sizeof(int) * 100);

What does it return?

If successful, malloc() returns an address to the memory it allocated. We use a pointer to store this address.

// Now "numbers" is a pointer to the base address of 100 integers.
// In other words, "numbers" is an array of 100 integers.
int *numbers = malloc(sizeof(int) * 100);

If malloc() fails, it will return NULL instead.

// Attempting to allocate memory for 10,000,000,000 integers.
// There is very likely not enough memory, so malloc() returns NULL.
int *numbers = malloc(sizeof(int) * 10E10);

Let’s do some malloc()ing!

#include <stdlib.h>

int main(void)
{
  while (1)
  {
    malloc(sizeof(int));
  }

  return 0;
}

Nooooo! This is all wrong.

This program is continuing to allocate memory without returning it to other programs. It is such a hog, leaking memory all over the floor. Don’t be a menace to your computer.

We need some way to return this memory when we’re done with it. Since it isn’t statically allocated, this is not an automatic process.


Introducing free()