Previous Page
Next Page

12.1. Allocating Memory Dynamically

The two functions for allocating memory, malloc( ) and calloc( ), have slightly different parameters:


void *malloc( size_t size );

The malloc( ) function reserves a contiguous memory block whose size in bytes is at least size. When a program obtains a memory block through malloc( ), its contents are undetermined.


void *calloc( size_t count, size_t size );

The calloc( ) function reserves a block of memory whose size in bytes is at least count x size. In other words, the block is large enough to hold an array of count elements, each of which takes up size bytes. Furthermore, calloc( ) initializes every byte of the memory with the value 0.

Both functions return a pointer to void, also called a typeless pointer. The pointer's value is the address of the first byte in the memory block allocated, or a null pointer if the memory requested is not available.

When a program assigns the void pointer to a pointer variable of a different type, the compiler implicitly performs the appropriate type conversion. Some programmers prefer to use an explicit type conversion, however.[*] When you access locations in the allocated memory block, the type of the pointer you use determines how the contents of the location are interpreted. Some examples:

[*] Perhaps in part for historic reasons: in early C dialects, malloc( ) returned a pointer to char.

    #include <stdlib.h>                         // Provides function prototypes.
    typedef struct { long key;
                     /* ... more members ... */
                   } Record;                    // A structure type.

    float *myFunc( size_t n )
    {
      // Reserve storage for an object of type double.
      double *dPtr = malloc( sizeof(double) );
      if  ( dPtr == NULL )                      // Insufficient memory.
      {
        /* ... Handle the error ... */
        return NULL;
      }
      else                                      // Got the memory: use it.
      {
        *dPtr = 0.07;
        /* ... */
      }

      // Get storage for two objects of type Record.
      Record *rPtr;
      if  ( ( rPtr = malloc( 2 * sizeof(Record) ) == NULL )
      {
        /* ... Handle the insufficient-memory error ... */
        return NULL;
      }
      // Get storage for an array of n elements of type float.
      float *fPtr = malloc( n * sizeof(float) );
      if ( fPtr == NULL )
      {
        /* ... Handle the error ... */
        return NULL;
      }
      /* ... */
      return fPtr;
    }

It is often useful to initialize every byte of the allocated memory block to zero, which ensures that not only the members of a structure object have the default value zero, but also any padding between the members. In such cases, the calloc( ) function is preferable to malloc( ). The size of the block to be allocated is expressed differently with calloc( ). We can rewrite the statements in the previous example using the calloc( ) function as follows:

    // Get storage for an object of type double.
    double *dPtr = calloc( 1, sizeof(double) );

    // Get storage for two objects of type Record.
    Record *rPtr;
    if  ( ( rPtr = calloc( 2, sizeof(Record) ) == NULL )
    {  /* ... Handle the insufficient-memory error ... */  }

    // Get storage for an array of n elements of type float.
    float *fPtr = calloc( n, sizeof(float));


Previous Page
Next Page