1. Overview
Memory is one of the most important components of computer systems. It is always beneficial to know how the operating system manages the memory. It can be very useful for developing software components. In this tutorial, we’re going to discuss the concept of dynamic memory using the C programming language and give some information about common errors.
2. What Is Dynamic Memory?
When the application loads into the system memory, it is generally divided into three main regions: stack, heap, and code. The figure below shows the general view of memory allocation for an application:
The stack region is responsible for storing the program’s local variable. Variables and arrays at the start of a function, including the main, sits in the stack space. The stack grows from high address to low address.
On the other hand, the heap region is responsible for dynamic memory allocation. Unlike stacks, heaps grow from low address to high address. By the way, it is important to keep in mind that the heap area is nothing related common with the heap data structure. While instructions sit in the code space, global and static variables go into the static/global part.
3. Dynamic Memory Allocation
The term dynamic memory allocation refers to the process of managing system memory while it is running. The malloc(), calloc(), realloc(), and free() are the four functions that perform dynamic memory management in the C programming language. The C standard library header file stdlib defines these four dynamic memory allocation functions of the C programming language.
Dynamic memory allocation utilizes the heap space of the system memory. Let’s take a closer look at the four dynamic memory management functions.
3.1. malloc()
malloc() is a function that allocates a heap block of memory. In particular, it allocates a specified number of bytes to the user but does not initialize them. The application uses a pointer returned by malloc() to access this block of memory once it has been allocated. It returns a pointer of type void by default, however, we can cast it into a pointer of any data type. If there isn’t enough room for the amount of memory requested by malloc(), the allocation will fail and it returns a NULL pointer. Its only argument is the size of the memory chunk to be allocated.
3.2. calloc() and realloc()
calloc() or contiguous allocation is similar to malloc but in this function, we can also specify the number of blocks of memory to be allocated. Unlike malloc, it takes two arguments: the number of memory blocks to be allocated and the size of each memory block. It initializes each block by value 0. We usually prefer to use calloc() when we want all the members of a structure initialized to zero.
On the other hand, realloc() stands for re-allocation. When memory allocated previously may not be sufficient, we may need more memory. In this situation, we can use realloc() to reallocate the memory dynamically.
3.3. free()
We use the free() function in C to dynamically de-allocate the memory. When we use malloc() or calloc() to allocate memory, the memory isn’t de-allocated on its own. That’s why we need to use the free() method to de-allocate the memory.
4. Common Errors
Incorrect usage of dynamic memory allocation is a common source of issues. Security flaws or program crashes, most commonly due to segmentation faults are examples of common errors.
The most common errors are can be summarized as follows:
- Not checking for allocation failures
- Memory leaks
- Logical errors
4.1. Not Checking for Allocation Failures
As we’ve mentioned, an allocation memory operation may not be successful always, and it may return a null pointer instead. If we use the returned value without checking if the allocation is successful, we’ll get unexpected results. This usually results in a crash. Due to the null pointer, we’ll have a segmentation fault. However, there is no guarantee that this will happen, therefore relying on it might potentially cause difficulties.
4.2. Memory Leaks
Non-reusable memory is one of the issues that comes with the failure to deallocation memory using the free function. The program may not use this any longer and this wastes memory resources. This situation may lead to allocation problems when the resources are exhausted.
While in C there is no advanced concept to mitigate memory leaks, in C++, Resource Acquisition is Initialization (RAII) concept provides exception safety, encapsulation, and locality. Therefore, it allows developers to handle memory leaks.
4.3. Logical Errors
Logical errors are the other type of common errors while handling dynamic memory allocation. As we’ve discussed, every allocation has a similar pattern. They start with the allocation with malloc, data storage with use, and deallocation with the free function. Trying to use the memory after a call to free (dangling pointer) or before a call to malloc (wild pointer), calling free twice and similar logical errors can cause a segmentation fault and this may result in a crash of the application. These issues can be difficult to diagnose.
5. Conclusion
In this tutorial, we explained what dynamic memory is and gave some information about dynamic memory allocation in the C programming language. We also mentioned the functions and common errors in dynamic memory allocation.