Dynamic memory allocation in C
Tags: c, memory, basics, beginners
Published: 2019-12-25 17:18:03

---
title: Dynamic memory allocation in C
published: true
description: Assigning memory dynamically with pointers in the C programming language
tags: C, memory, basics, beginners
series: Basics of the C programming language
---

####Overview

This post deals with pointers because dynamic memory allocation only works with pointers.
Whenever you define a variable in C, the compiler automatically allocates the correct amount of memory based on the data type that is declared.
However, it is frequently desireable to be able to dynamically allocate storage while a program is running, e.g. if you want to change the value of, or concatenate to a string, or if you have a program that is designed to read in a set of data from a file into an array in memory. To allocate memory in C, there are three options:

1. define the array to contain the maximum possible number of elements at compile time
2. use a variable-length array to dimension the size of the array at runtime (available in the C99 standard)
3. allocate the array dynamically using the memory allocation routines availble in the C language

Allocating memory dynamically allows you to create pointers at runtime that are just large enough to hold the amount of data required for the task, and free it when no longer needed - ideal from an efficiency perspective.

#####Heap vs. Stack

There are two ways to store memory in a C program (two data structures): in the heap, or in the stack. These will not be covered in depth, but the heap is where dynamically allocated memory reserves space. Memory in the heap persists longer than memory on the stack, and the programmer controls when it is freed.  
Things such as function arguments and local variables are stored in the stack, and the memory is automatically freed when a function ends.

The advantage of allocating memory, as with everything in programming, is a trade-off: you as the programmer must also keep track of the memory that has been allocated and remember to free it when it is no longer needed.

####Memory allocation in C

There are three functions in the standard library that allow you as the programmer to work with memory: `malloc()`, `calloc()`, and `realloc()`. To use them, include the standard library at the top of your file: `#include <stdlib.h>`

#####Memory allocation: malloc()

`malloc()` is the simplest standard library function that allocates memory at runtime. The number of bytes to be allocated is the argument, and it returns the address of the first byte of memory that it allocated. Because the return value is a memory address, it is declared as a variable to store the return value, which can only be a pointer (because only pointers can store memory addresses). The simplest way it can be declared is shown in the example below:

```c
int * pNumber = (int*) malloc(100);
```

In the above, 100 bytes of memory were requested, and the address is assigned to the pointer named `pNumber`, which points to the first byte in that location. Assuming an int takes up 4 bytes, it would hold 25 int values. However, this is not the ideal way to allocate memory, because different systems will have different sizes for integers.
The better way to use `malloc()` is to take the desired number of values to be stored, call the `sizeof()` operator to get the size of the data type, and then multiply the desired number of values by the value returned by `sizeof()`

```c
int * pNumber = (int*) malloc(25*sizeof(int));
```

Using the method above ensures that the exact amount of memory required to hold 25 integers is allocated, regardless of system (32 or 64 bit PC, or imbedded systems with different architecture like a raspberry pi or IOT device). Because malloc returns a void type pointer, you must always cast the return value to the correct data type when allocating memory - the `(int*)` in this case.
You can request any number of bytes, but if for some reason the amount requested cannot be allocated (e.g. there is not enough memory to do so for a huge amount requested), then `malloc()` returns a pointer with the value NULL. For this reason, as part the declaration, it is always a good idea to also include an immediate validation check and code to deal with a failure to allocate, so the complete code for `malloc()` would look like this:

```c
int * pNumber = (int*) malloc(25*sizeof(int));
if(!pNumber)
{
  // code to deal with the failure, such as an error message and program exit/abort
}
```

Remember, a NULL value is falsy, so the if loop will only run if `pNumber` is NULL or zero (boolean false in C). If the memory can't be allocated, it's best to throw an error and exit/abort the program, because it will crash later (e.g. when the program later tries to use the array) and it will be harder to determine why when debugging later.

#####Releasing memory

The memory will automatically be released when the program ends, but when you no longer need the memory, it is best practice to always release it, even if it's just before the program exits to avoid memory leaks.
A memory leak can occur when you allocate memory and do not retain a reference to it, and thus are unable to release it. This often occurs in a loop, and because it is not released when no longer required, the program will consume more and more on each loop iteration and eventually may occupy it all. Ideally, the function that allocates memory will be the one that releases it.
To release the memory, the standard library provides a `free()` function to do so. The `free()` function has a formal parameter of type `void*`, which means any type of pointer can be passed to it as an argument. As long as the pointer contains the original address that was returned when the memory was allocated, the entire block of memory will be freed.
The pointer should always be set to NULL after the memory has been freed, the syntax of which is demonstrated below:

```c
free(pNumber);
pNumber = NULL;
```

#####Continuous allocation: calloc()

The `calloc()` function is similar to `malloc()`, the difference being that it _initializes_ the memory after it is allocated so that all bytes are zero. It takes two arguments, the number of data items required, and the size of each data item. So, the declaration looks a lot like `malloc()`, except the number of items is its own argument, and you don't need to manually multiply it by the size:

```c
int * pNumber = (int*) calloc(75, sizeof(int));
```

The return value will be NULL if it is not possible to allocate the memory requested.

#####Reallocating memory: realloc()

The `realloc()` function could be described in simple terms as 'copy and make bigger.' It enables you to reuse or extend memory that you previously allocated using `malloc()` or `calloc()`. It expects two arguments: a pointer containing an address that was returned by a previous `malloc()` or `calloc()` call, and the size in bytes of the new memory required.
What it will do 'under the hood' is to transfer the contents of the previously allocated memory referenced by the pointer that is passed in to a new (larger) location. The important feature of `realloc()` is that it preserves the contents of the original memory area.
It returns a `void*` type pointer to the new memory if successful, or NULL if the operation fails.
An example of the syntax:

```c
#include <stdio.h>

int main()
{
  char * str = NULL;

  //initial memory allocation
  str = (char *) malloc(15 * sizeof(char));
  strcpy(str, "mikkel");
  printf("String: %s, Address: %p \n", str, str);

  //reallocating the memory to make it larger
  str = (char *) realloc(str, 25 * sizeof(char));
  //check the string and memory address after reallocation
  printf("String: %s, Address: %p \n", str, str);

  free(str);

  return 0;
}
```

Some caveats:

- Avoid allocating lots of small blocks of memory. Because allocating memory on the heap carries some overhead, allocating many small blocks will carry much more computational overhead than allocating fewer larger blocks.

- Only hang on to memory as long as you need it. Free it as soon as you are finished with it.

- Always ensure that you provide for releasing memory that was allocated - a good guideline is to decide where in the code to release it when you write the code that allocates it.

- Make sure not to inadvertently overwrite the memory address that was allocated in the heap before it is released. This will cause a memory leak. A related warning is to be careful when allocating memory within loops.