Arrays of Pointers

Pointers, like other variables, can be stored in arrays. This feature allows you to create a variety of useful data structures.

Summary: In an array of pointers, each array element is a pointer variable.

If you find an array of pointers hard to picture, begin with the idea that an array is a group of variables of the same type. An “array of pointers” is also a group of variables, but instead of simple variables, it contains a group of pointer variables.

Each element in an array of pointers, then, is a pointer that contains an address. Like other array elements, each element can be accessed with a numerical subscript.

Pointer arrays are often used to speed up sorts. The QCSORT.C program shows the basic idea behind such a sort:

/* QCSORT.C: Demonstrate sorting array of pointers. */

#include <stdio.h>

#define SIZE 4

void sort( int size, double *p[] );

void show( int size, double *p[], double dd[] );

main()

{

int x;

double d[] = { 3.333, 1.111, 2.222, 4.444 };

double *d_ptr[SIZE];

for( x = 0; x < SIZE; x++ )

d_ptr[x] = &d[x];

show( SIZE, d_ptr, d );

sort( SIZE, d_ptr );

show( SIZE, d_ptr, d );

}

void sort( int size, double *p[] )

{

int x, x1;

double *temp;

for( x = 0; x < size - 1; x++ )

for( x1 = x + 1; x1 < size; x1++ )

{

if( *p[x] > *p[x1] )

{

temp = p[x1];

p[x1] = p[x];

p[x] = temp;

}

}

}

void show( int size, double *p[], double dd[] )

{

int x;

printf( "------------------------" );

printf( "------------------------\n" );

for( x = 0; x < size; x++ )

{

printf( "*d_ptr[%d] = %1.3f ", x, *p[x]);

printf( "d_ptr[%d] = %u ", x, p[x]);

printf( " d[%d] = %1.3f\n", x, dd[x] );

}

}

Here is the output from QCSORT.C:

------------------------------------------------

*d_ptr[0] = 3.333 d_ptr[0] = 66 d[0] = 3.333

*d_ptr[1] = 1.111 d_ptr[1] = 74 d[1] = 1.111

*d_ptr[2] = 2.222 d_ptr[2] = 82 d[2] = 2.222

*d_ptr[3] = 4.444 d_ptr[3] = 90 d[3] = 4.444

------------------------------------------------

*d_ptr[0] = 1.111 d_ptr[0] = 74 d[0] = 3.333

*d_ptr[1] = 2.222 d_ptr[1] = 82 d[1] = 1.111

*d_ptr[2] = 3.333 d_ptr[2] = 66 d[2] = 2.222

*d_ptr[3] = 4.444 d_ptr[3] = 90 d[3] = 4.444

Since the purpose of QCSORT.C is to demonstrate pointers, not sorting methods, it uses a simple bubble sort. This method isn't efficient but has the advantage of being short and easy to follow.

The QCSORT.C program creates a double array named d and an array of pointers named d_ptr. Each array has four elements. To illustrate the sort, the elements of d are initialized out of order.

The goal of QCSORT.C is to display a sorted list of the values in d. You could do this by sorting the elements of d itself, but that solution is not efficient. Every double value contains eight bytes, and sorting a large number of double values requires that you move a lot of memory.

Instead of moving the double values themselves, QCSORT.C creates an array of pointers that point to the elements of the d array, then sorts the pointers. This saves time because a pointer is stored in only two bytes. Figure 8.6 shows the relationship between the d and d_ptr arrays immediately after both are initialized.

At the stage shown in Figure 8.6, the pointers in the d_ptr array have been initialized to point to the double elements in the d array. (The array element d_ptr[0] points to d[0], d_ptr[1] points to d[1], and so on.) The function show displays three sets of data:

The value each pointer references

The address assigned to each pointer

The value of each element in the d array

After calling the show function, QCSORT.C calls the sort function, which sorts the pointers in d_ptr.

The declaration of sort contains something new. In the declaration

void sort( int size, double *p[] );

the expression *p[] shows that the sort function expects to receive a pointer to an array of pointers. When the program calls sort, it passes the size of the array to be sorted (first argument) and a pointer to the array of pointers (second argument):

sort( SIZE, d_ptr );

Now the sort function has all the information it needs to sort the pointers in the d_ptr array, making each pointer point to the correct element in the d array.

After the sort is complete, QCSORT.C calls show again to display the results of the sort. Now that the pointers have been sorted, they can be used to display a sorted list of double values. Figure 8.7 shows the relationship between the d and d_ptr arrays after the sort is complete.

Of course, the array in QCSORT.C is so small that the time savings from using pointers is negligible. In a real program, however, which might sort thousands of values instead of four, the difference between moving eight bytes and two bytes can be dramatic. The advantage of sorting pointers is even greater when sorting large data objects such as strings or structures.

Summary: The elements in a pointer array can point to any type of data.

The QCSORT.C example section uses a fairly simple array of pointers. But you can use such arrays to create quite complex data structures. The basic form of the array is always the same—it is a group of pointer variables, each pointer accessible through a subscript—but the pointers in an array can point to any kind of data object. You can have an array of pointers to structures, an array of pointers to strings, and so on. The only difference is in what the pointers reference.

Don't confuse an array of pointers with a pointer to an array. A pointer to an array (or “array pointer”) is a single pointer variable that points to an array element. The single pointer can access any element of the array, but only one pointer is involved.

In contrast, an array of pointers is a group of related pointer variables stored in an array. Each element in the array is a pointer, and you can access individual pointers with the array name and subscript. Each pointer in the array points, in turn, to some other object.