In many cases, it is impossible to know (or impractical to determine) when a C program is written and compiled, how much memory will be used by the program when it executes.
One approach to this problem is to have the programmer figure out, when he or she is writing the program, how much space it will require (or impose arbitrary limits on how much space the program can use), and write their code accordingly. This approach is insufficient for many common kinds of programs, however. For example, imagine how wasteful it would be if your word processor were written in such a way that it always grabbed enough memory so that it could edit an encyclopedia, even if all you ever edited with it was your grocery list.
Dynamic memory allocation is a way to defer the decision of how much memory is necessary until the program is actually running, get more if you run out, or give back memory that your program no longer needs.
The malloc (memory allocation) function is the most frequently used function for dynamically allocating memory. malloc has the following prototype:
void *malloc(unsigned int size);
The size parameter indicates the number of bytes of memory that you wish to allocate. If there is sufficient memory available, then malloc returns a pointer to the start of a span of memory large enough to hold size bytes. If sufficient memory is not available, the malloc returns a NULL pointer. (NULL is a constant defined as part of ANSI C, and its actual definition resides in stdio.h. If you try to compile a file and you get error messages about NULL not being defined, check to make sure that you are #include'ing stdio.h.)
Because malloc can return NULL instead of a usable pointer, your code should always check the return value of malloc in order to see whether it was successful- because if it wasn't, and your program dereferences the resulting NULL pointer, your program will crash. In the example code given here, I'll usually omit this check in order to keep the code short and uncluttered- but in your own code, don't neglect this check.
Also note that memory allocated by malloc has undefined values- there's no telling what values reside in those bytes. It is a mistake to assume that the memory is filled with zeros or some other value. Most of the time when you use malloc, the first thing that you will do is initialize all of the memory you allocated to some known values. (Because zero is the most common initial value, another function named calloc also exists in the standard library. calloc is similar to malloc, but takes different arguments; see its manual page for more info.)
Calculating how many bytes are necessary to store items of different types is made simpler by the sizeof operator. The sizeof operator evaluates to the number of bytes necessary to represent a specific C type or variable. For example, on the HP machines:
sizeof (char) == 1 sizeof (int) == 4 sizeof (double) == 8
Even if you know what the size of something is, it is considered very poor style to use that number instead of relying on sizeof, because this makes porting your code from one platform to another difficult- and one tiny error can have strange and hard-to-diagnose results.
The return type of malloc is a void pointer. A void pointer may point to an object of any type, and therefore C allows a void pointer to be assigned to a pointer variable of any type.
For example, imagine that you wanted to allocate an int, and then assign 31 to this new integer:
int *x = malloc (sizeof (int)); *x = 31;
This results in the following arrangement:
Note that this new int does not have a name; the only way we can refer to it is as the int that x points to. (Of course, we could create other pointers that pointed to the same place that x does, but in this code fragment x is the only pointer we have).
As a further (and more farfetched) example, consider the following:
int **y = malloc (sizeof (int *)); *y = malloc (sizeof (int)); **y = 42;
This results in the following arrangement:
Note again that the int pointer pointed to by y has no name, nor does the int it points to. The only way to reference this new int at this point is through two levels of indirection.
When your program is finished using whatever memory it dynamically allocates, it can use the free function to tell the system that the memory is available again.
Take care to only free pointers that were returned from malloc (or one of its relatives); otherwise, you might free some memory that you didn't allocate, deallocating memory that might still be in use by some other part of your program. Many modern versions of free are intelligent enough to recognize when the program tries to free a bogus pointer, but not all of them do.