C stores variables in different “classes” of storage. These storage classes follow different rules for how long information in them stays around (“persists”). Which class your declared variable is placed into depends on the placement and form of the declaration.
Most common is the “local” storage class. A local variable is declared by simply placing its declaration inside a subroutine. This does two things:
Next, we have “global” variables. These variables are declared by placing their declarations outside all subroutines. Their names are available to any subroutine which follows their declaration in the same file, and are also available to other files, if their declaration is repeated, preceded by the work “extern”. Only one copy of each global variable exists for the entire program, and storage for such variables is initialized to zero automatically. They serve as shared variables, so that one subroutine can pass data to another “under the table”.
Next, there are “static” variables. These are variables declared with the keyword “static”, inside a subroutine.
One copy of each is created, no matter how many times the subroutine is called (recursively). The variable name is known only to the subroutine in which its declaration occurs.
Finally, there is “heap” storage. An area of memory, called the “heap” is maintained, separate from the stack.
Blocks of memory from the heap are reserved by calling the library routine “malloc”, and each block should be freed for re-use by calling the library routine “free”. Areas of memory reserved by malloc are kept around until explicitly freed by free().
Malloc() and Free()
The details of this storage allocation package can be found by doing “man malloc” at a UNIX prompt
The signatures of these functions are as follows:
#include <stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
malloc() accepts the number of bytes in the area you want to allocate as an argument, and returns a pointer to the allocated region, or a null pointer, if there’s no more memory. The allocated memory is not initialized, and contains garbage initially. Note that the pointer returned has “void” type. Before being saved, or used, the pointer must be “cast” to a concrete type. malloc() is typically used to create an array or variable which should persist after the creating subroutine returns.
Example:
int A; /* A is the array I want to build, containing N inst’s */
A
= (int *) malloc(N*sizeof(int));
The
elements of A, A[0] through A[N-1] should now be set to some useful values, and
used. If the subroutine which executed
the code above wants to do so, it can legitimately return the value of A, which
is the pointer that malloc() returned.
Other programs can use this pointer to access elements of A.
The (int *) preceding malloc() is called a “cast”. It tells C to change its idea of what the following expression points to, to a pointer to “int”. This is one way of fooling the C type system. The result of this cast is a pointer to an int, with exactly the same value as the pointer that malloc() returned. When your program uses A, C will use “integer” instructions on the object A points to.
After all uses of A have completed, and A is no longer needed, some subroutine should execute:
free(A);
to
release A’s storage for re-use. (If you
don’t do this carefully, your program can grab more and more heap storage,
until all such storage is used up. This
usually causes a crash. The SYSTEM won’t
crash – allocated storage is returned to the OS when the program terminates.)