Back to DFS's C Page


Dynamic Memory Allocation

Basic information about pointers can be found on the Simple Pointers page.

The topics discussed on this page:

The operating system maintains an area of memory known as the heap. This memory can be requested by a program by specifying how much is needed. The operating system responds by returning a pointer to a block of the requisite size if it is available. Since memory is a finite resource (contrary to the belief of Microsoft), it is the programmer's responsibility to ensure that the memory has indeed been made available. The operating system will return a NULL pointer, if enough memory is not left on the heap. This section will address all of these issues.

Why do we need variable amounts of memory?

When the programmer is writing a program, it may not be known how many items of data will need to be dealt with. One way to handle this is to declare overly large arrays, ones that will surely provide enough memory. This is, however, potentially very wasteful. Moreover, if many data structures are declared in this way, you could use up all of the memory available. Besides this, you may not need all of the allocated for the whole time the program is running. An example of this type of program is one for graphics design. At compilation time, it cannot be known how many images the user will want to have on hand at any given moment. These situations require dynamic memory allocation.

A Simple, Practical Example Using Coordinate Pairs

An easy to understand and very practical example is one in which a program needs to process a list coordinates of points. This could be a short list or a very long one. If the data is read from a file, the programmer has no idea how many pairs of coordinates are going to be provided until they are read in.

The array of structures program uses the coordinates of two points to determine the slope of the line segment defined by the points. The rectangle drawing program reads four pairs of coordinates from a file and draws the rectangle (or other quadrilateral) defined by the points in an X Window. Here we will look at the program segments which would allow us to read in, store, and then print out a list of coordinates of unspecified length. The complete sample program is provided at the end of this page.

Defining a Structure for a Linked List

If we are going to avoid using an array to store (and relate together) a number of structures each of which contains a coordinate pair, we still need a way to link the structures together. The following definition does this. However, remember this definition does not cause any memory to be allocated.

struct point
  {
    float x;
    float y;
    struct point *nx;
  };

As with the programs mentioned above, this structure contains the data for the x and y coordinates. The addition here is a pointer to another point structure. nx is a customary abbreviation next, aiding the programmer with visualizing the list.

A Pointer to a Linked List

Since no memory is allocated by the above structure definition, we need to be prepared for when we request memory from the heap.

   struct point *figure = NULL;

This line declares a pointer to an unspecified, and still unallocated, point structure, which results in the use of four (4) bytes of RAM. To indicate that there is not yet any structure that actually holds data, the pointer is assigned the value NULL, which is an illegal memory location in RAM. In this way, it is easy to check if there are any structures in the list.

   if( !figure )
   {
      printf("There are no points in %s.\n", infile);
      exit(1);
   }

The expression !figure will be TRUE if figure is NULL, resulting in the if structure's statements being executed.

Memory Allocation for a Structure

To request memory from the heap, the built-in function malloc(), memory allocation, is passed the size of the structure. This is accomplished by using the built-in function sizeof(), which will return the number of bytes of any specified data type, here the programmer-defined point structure.

   newptr = (struct point *)malloc(sizeof(struct point));

malloc() returns a char pointer which needs to be cast to one of the appropriate type. If the value returned is NULL, the programmer knows that the request has been denied.

Assigning Values to the Structure

If the coordinates for the new structure are stored in tempx and tempy, the newly allocated structure can be assigned values by the following statements.

   /* store coordinates */
   newptr->x = tempx;
   newptr->y = tempy;
   /* pointer to NEXT struct is NULL (no next exists yet) */
   newptr->nx = NULL;

Adding the Structure to the List

Two different situations may exist: the list is currently empty or it already contains one or more structures.

Using the Data in the List

To access data in the list, we use a technique similar to that used for appending a new structure to the list. In the program at the end of this page, flow gets to the section which prints the contents of the list only if the list is not null -- if the named file does not exist or if it does not contain suitable data, the program would have exited. Consequently, a do-while loop with no check for the list being null is sufficient. If the user were entering data and the coordinates were being printed from the list, this might be done differently.

   /* set temp ptr to start of list */
   tptr = figure;
   /* repeatedly print data while tptr points to a struct */
   do {
      printf( "(%.2f, %.2f)\n", tptr->x, tptr->y);
      tptr = tptr->nx;
   } while(tptr);

Returning Memory to the Heap

When we are done using the list, it is good programming technique to return the memory to the heap. There are two places in the program where this is done using the following function call.

   freedata(figure);
  1. The obvious situation is when we are about to exit the program after printing out the list of coordinates.
  2. The other circumstance occurs if we run out of available RAM before we finish reading in all of the coordinates from the file. At this point as well we should free up the memory that has been allocated.

In other words, before we allow the program to end, we should always free any memory obtained from the heap. Here is the code for the function to release the memory.

void freedata(struct point *p)
{
   struct point *temp;

   /* bulletproofing for no items in list */
   if(p == NULL) return;
   do {
      /* save ptr for next struct */
      temp = p->nx;
      /* free memory for current struct */
      free(p);
      /* assign ptr-for-next to ptr-for-current */
      p = temp;
   } while(p);
}

The Complete Sample Program

This program reads in an arbitrary number of pairs of float values from a file and prints them as coordinates of a series of points.

#include <stdio.h>

#define TRUE 1
#define FALSE 0

/* Global structure declaration */
struct point
  {
    float x;
    float y;
    struct point *nx;
  };

/* function prototypes */
void freedata(struct point *p);

void main(int argc, char *argv[])
{
   struct point *figure = NULL;
   struct point *tptr, *newptr;
   float tempx, tempy;
   int howmany;
   int num_points = 0;
   FILE *fpin;
   char infile[80]; /* filename */

   /* read in data for coordinates */
   strcpy(infile, argv[1]);
   fpin = fopen(infile, "r");
   /* if fpin is NULL, it was unable to open file for reading */
   if ( !fpin)
   {
      printf("%s does not exist.\n", infile);
      exit(1);
   }
   do   /* keep reading & saving until no more coordinate pairs found */
   {
      howmany = fscanf(fpin, "%f%f", &tempx, &tempy);
      /* if BOTH coordinates gotten */
      if (howmany == 2)
      {
         /* get RAM for new struct; newptr gets address */
         newptr = (struct point *)malloc(sizeof(struct point));
         /* bulletproofing for running out of RAM */
         if( !newptr )
         {
            printf("Ran out of memory after %d points.\n", num_points);
            /* free up already allocated memory */
            freedata(figure);
            exit(1);
         }
         /* store coordinates */
         newptr->x = tempx;
         newptr->y = tempy;
         /* pointer to NEXT struct is NULL (no next exists yet) */
         newptr->nx = NULL;
         /* if no points yet, attach to base pointer */
         if(figure == NULL)
            figure = newptr;
         else
         {
            /* find last struct */
            tptr = figure;
            while(tptr->nx)
               tptr = tptr->nx;
            /* attach to last struct */
            tptr->nx = newptr;
         }
         num_points++;
      }
   } while (howmany == 2);
   fclose(fpin);

   /* if pointer is NULL, no coordinates found -- so exit */
   if( !figure)
   {
      printf("There are no points in %s.\n", infile);
      exit(1);
   }

   /* print the set of coordinates */
   printf("The points are:\n");

   /* set temp ptr to start of list */
   tptr = figure;
   /* repeatedly print data while tptr points to a struct */
   do {
      printf( "(%.2f, %.2f)\n", tptr->x, tptr->y);
      tptr = tptr->nx;
   } while(tptr);

   /* free RAM for all structures */
   freedata(figure);
}

void freedata(struct point *p)
{
   struct point *temp;
   /* bulletproofing for no items in list */
   if(p == NULL) return;
   do {
      /* save ptr for next struct */
      temp = p->nx;
      /* free memory for current struct */
      free(p);
      /* assign ptr-for-next to ptr-for-current */
      p = temp;
   } while(p);
}

Back to Top


Created 20 Jan 1999
Revised 24 Jan 1999
© DFStermole 1999