This C programming tutorial deals with the use of memory management functions under C. While there are no built in functions for creating memory blocks, the standard libraries provide functions to make this available to the programmer.
Before you begin, it might be worthwhile to take a quick look at the C Header File tutorial to refresh your memory regarding the use of C header files and libraries.
Also of note might be the General Programming series, for those not totally familiar with programming concepts in general. For example, it is in this set that we first described data types, and pointers to areas of memory.
The principle behind memory management is to be able to allocate memory from the local heap, manipulate it, perhaps reallocate it to make the block bigger or smaller, and finally to release the memory back to the operating system.
In C, all memory operations require void pointers (void *), which can be cast to any other type by the compiler. This allows us to denote a block of memory as containing objects of any built-in or user defined data type.
The only point to remember is that different implementations of C will potentially use different representations for built in data types. This means that it is wise to always use the sizeof function to derive the data type size rather than assuming that it will be of a certain size when calculating memory requirements.
The malloc function allows the programmer to create a block of memory of a given size:
Using it is as easy as it seems. First we need to decide how many objects of a specific data type we want to store initially, and then we create the block with malloc, casting back to the data type to get a pointer to an array of objects:
This snippet would allocate a block of memory sufficiently large to contain 10240 characters. If not enough memory is available, then NULL will be returned.
If we decide, during the execution of the program, that we might need to expand, or contract this memory block, we can use the realloc function:
The function is non-destructive. In other words, should there not be enough memory available, the resulting data block may be smaller than requested. However, if the new block is smaller than the old block, then any data objects at the end will be returned to the operating system, lost forever.
There is no need to cast the pointer back to a void, when using realloc, as the compiler will handle this by itself.
Finally, when the memory block is no longer used, then it must be returned back to the operating system, by calling the free function:
Once this has been executed, the pBlock is returned to NULL, and the data present in the allocated memory block is lost. It is vital that all memory that has been allocated using malloc, or realloc, is returned to the operating system in this way.
Different platforms put different restrictions on memory management. While most modern operating systems now have a flat memory model, it is worth remembering that some will have a segmented model. Segmentation was introduced to allow applications access to 'extended' or 'expanded' memory over and above the local heap allocated to the operating system.
Even Windows has now abandoned the segmented model in place of a model in which all the available memory is accessible through malloc. However, it is worth checking the platform specific notes to make sure that there are no limits on the local heap before embarking on memory hungry application development.