Malloc: Dynamic Memory Management in C

malloc cMalloc is one of a small group of routines that are designed for dynamic memory management in C. Its purpose is to allocate memory for use by a program, while that program is running, and in quantities that are difficult to estimate at design time. For example, when you can’t be certain of how much memory is available on the machines on which the program will be run, or when working with data that is highly changeable in size – such as in word processors which cannot know how large a file the user will attempt to open.

To understand how, and why, to use dynamic memory management in your programs, you should have a reasonable grasp of the basics of programming in C – especially topics like using pointers and data types – Learn C Programming Language can help you with this. Malloc and its associated functions are used in many languages derived from C, so studying C++ programming from a beginner level or how to code in Objective C (also for beginners) also provides the necessary background information and environments in which to use the techniques described below.

Dynamic Memory Management

In the early days of computing, it was common for only one program to run at a time, and this program had complete access to all of the memory available in the machine. Even then, it was easy for a programmer to lose track of which areas of memory were in use and which were free. Malloc, part of the C standard library (stdlib.h), offered a simple mechanism to help manage this situation. As computer systems became more complicated, operating systems took control of memory management to enforce the cooperation of many programs all running at the same time. Malloc evolved into a way of communicating with the operating system to make requests for additional memory.

Many modern programming languages, such as C#, automatically handle dynamic memory management (including “garbage collection” – reclaiming memory that is no longer needed by a program). However, when writing C programs, particularly for use on older computing platforms, the correct and efficient use of memory management techniques is vital. Thankfully, and despite the high importance placed on their use, there are only a handful of functions to learn.

When you declare a variable in C, it will be placed in an area of memory called the stack, which usually provides fast access to values. But when allocating memory dynamically, an area called the heap is used instead.

Allocation of Memory with Malloc

Malloc is a very simple function, with only one parameter and returning one value. The declaration of this function is:

void *malloc(size_t size)

To allocate memory: call the function mallocand specify the number of bytes required as the argument. If the allocation is successful, the function returns a pointer to the area of memory to be used. If the allocation is unsuccessful, the returned value is NULL.

Because malloc returns a void*, the allocated memory can be used for a wide variety of purposes and cast to various data types. In the following example, the memory is accessed as an array of character bytes:

#include "stdafx.h"
#include <stdlib.h>

int _tmain(int argc, _TCHAR* argv[])
{
// Allocate 512 bytes of memory
char *buffer = (char*)malloc(512);

if (buffer != NULL) {
// Populate the memory with random numbers
for (int i=0; i < 512; i++)
buffer[i] = (char)rand();

// Free the memory before exit
free(buffer);
}

return 0;
}

De-allocation of Memory

After memory is allocated with malloc, and you have finished using it in your program, it must be returned to the system using the function free(). Failure to do so can result in the computer running out of memory, or the operating system terminating your program unexpectedly.

When calling free, use the pointer returned by a successful call to malloc as the argument, as shown in the example above:

free(buffer);

Calloc vs. Malloc

Calloc is a very similar function, but one that was designed to make it easier to allocate memory for use with arrays. Instead of accepting the size (in bytes) of the total amount of memory needed, it accepts two arguments:

void *calloc(size_t nitems, size_t size)

The first defines the number of items that the array must be able to hold, and the second argument specifies the size of each item in bytes. The total amount of memory requested would be nitems multiplied by size.

You should also be aware that malloc does not clear, or zero, the memory range that it allocates to a program. However, calloc does – all bytes in the memory range allocated to the array will be set to zero.

Re-allocation of Memory Using Realloc

With realloc you can resize a block of memory that was allocated to the program by calls to calloc or malloc, even if the memory area is already in use. If the new block is larger than the previous one then the data will not be affected but may be moved automatically to a different location on the heap. If the new block is smaller, some of the existing data may become inaccessible.

Realloc has the following declaration:

void *realloc(void *ptr, size_t size)

The first accepted argument is a pointer to an existing block of memory allocated by an earlier call to malloc or calloc; the second argument is the new size required. Again, if the allocation is successful then a pointer to the new memory is returned, but NULL is returned if the allocation failed.

Common Problems

There are few common mistakes made by programmers (and not only beginners) when using dynamic memory management techniques. In modern systems, the operating system may terminate your program if it detects any of the following behaviors:

  • Forgetting to free memory when it no longer needed – which can cause the system to run out of memory.
  • Freeing memory that has already been freed – if you have more than pointer referring to exactly the same area of memory then you should only call free() for one of those pointers.
  • Accessing de-allocated memory – once an area of memory has been de-allocated, your program should not attempt to access it. This mistake often occurs when more than one pointer refers to the same block of memory.
  • Accessing more memory than was allocated – when using array addressing syntax or when manually incrementing/decrementing a pointer, you must be careful not to move past the area of the memory that was allocated for your use.
  • Forgetting to initialize memory when using malloc – do not assume that the memory allocated by malloc is full of zeroes, only calloc actively clears memory.

Further Study

Due to the heavy use of pointers with dynamic memory management, it can be tricky for new programmers to C to write stable, well-tested code that is free of memory-handling problems. C Programming for Beginners teaches C programming from the ground up, and covers use of pointers and memory management.