The C programming language supports dynamic memory allocation in the malloc(3), calloc(3), realloc(3), and free(3) functions. These functions enable you to obtain, manipulate, and return memory from the operating system on an as-needed basis. Dynamic memory management is essential to efficient programming. Besides more efficient use of memory, a critical system resource, dynamic memory management frees you from coding arbitrary limits in your code. Instead of hitting an artificial size constraint in an array of, say, strings, you can simply request more and avoid unnecessary hard-coded limits. The following sections discuss each of these functions.
Using the malloc() Function
The malloc() function allocates an uninitialized memory block. It allocates a specified number of bytes of memory, as shown in the following prototype, returning a pointer to the newly allocated memory or NULL on failure: void *malloc(size_t size); Always check malloc()’s return value. It is not necessary to cast the pointer malloc() returns because it is automatically converted to the correct type on assignment, but you may encounter these casts in older, pre-ANSI code. The memory block you receive is not initialized, so don’t use it until you’ve initialized it. Memory obtained with malloc() must be returned to the operating system with a call to free() in order to prevent memory leaks.
Using the calloc() Function
The calloc() function allocates and initializes a memory block. It uses the following prototype: void *calloc(size_t nmemb, size_t size); This function acts very much like malloc(), returning a pointer to enough space to hold an array of nmemb objects of size size. The difference is that calloc() initializes the allocated memory, setting each bit to 0, returning a pointer to the memory or NULL on failure.
Using the realloc() Function
The realloc() function resizes a previously allocated memory block. Use realloc() to resize memory previously obtained with a malloc() or calloc() call. This function uses the following prototype: void *realloc(void *ptr, size_t size); The ptr argument must be a pointer returned by malloc() or calloc(). The size argument may be larger or smaller than the size of the original pointer. Increases or decreases should occur in place. If this is not possible, realloc() will copy the old data to the new location, but the programmer must update any pointer references to the new block. The following also apply to realloc()’s behavior:
- realloc() does not initialize the memory added to the block.
- realloc() returns NULL if it can’t enlarge the block, leaving the original data untouched.
- realloc() called with a NULL pointer as the first argument behaves exactly like malloc().
- realloc() called with 0 as the second argument frees the block.
Using the free() Function
The free() function frees a block of memory. This function uses the following prototype: void free(void *ptr); The ptr argument must be a pointer returned from a previous call to malloc() or calloc(). It is an error to attempt to access memory that has been freed. Memory allocation functions obtain memory from a storage pool known as the heap.
Memory, a finite resource, can be exhausted, so be sure to return memory as you finish using it. Beware, too, of dangling pointers. A memory leak occurs when allocated memory is never returned to the operating system. Dangling pointers are the uninitialized pointers left behind after memory is freed. Ordinarily, dangling pointers are not a problem. Trouble only arises when you try to access a freed pointer without reinitializing the memory to which it points, as this code snippet llustrates:
char *str; str = malloc(sizeof(char) * 4)
KABLOOIE! You will get a segmentation fault (SIGSEGV) on the last line.
Using the alloca() Function
The alloca() function allocates an uninitialized block of memory. This function uses the following prototype:void *alloca(size_t size); The dynamic memory allocation functions covered so far, malloc(), calloc(), and realloc(), all obtain their memory from the heap. alloca() behaves like these, except that it obtains memory from the process’s stack rather than the heap and, when the function that invoked alloca() returns, the allocated memory is automatically freed. Listing
14.1 illustrates the standard library’s memory management functions.