Pointers to Pointers

We introduced the concept of a pointer to a pointer previously. You can have a pointer to a pointer of any type.
Consider the following:

char ch;  /* a character */
char *pch; /* a pointer to a character */
char **ppch; /* a pointer to a pointer to a character */
We can visualise this in Figure 11.1. Here we can see that **ppch refers to memory address of *pch which refers to the memory address of the variable ch. But what does this mean in practice?
Memory address

Fig. 11.1 Pointers to pointers Recall that char * refers to a (NULL terminated string. So one common and convenient notion is to declare a pointer to a pointer to a string (Figure 11.2)
Pointer to Pointer

Fig. 11.2 Pointer to String Taking this one stage further we can have several strings being pointed to by the pointer (Figure 11.3)
Pointer to String

Fig. 11.3 Pointer to Several Strings We can refer to individual strings by ppch[0], ppch[1], ..... Thus this is identical to declaring char *ppch[].
One common occurrence of this type is in C command line argument input which we now consider.

Command line input

C lets read arguments from the command line which can then be used in our programs.
We can type arguments after the program name when we run the program.
We have seen this with the compiler for example
   c89 -o prog prog.c
c89 is the program, -o prog prog.c the arguments.
In order to be able to use such arguments in our code we must define them as follows:
   main(int argc, char **argv)
So our main function now has its own arguments. These are the only arguments main accepts.

  • argc is the number of arguments typed -- including the program name.
  • argv is an array of strings holding each command line argument -- including the program name in the first array element.
A simple program example:


#include<stdio.h>
 
main (int argc, char **argv)
    { /* program to print arguments
     from command line */
 
     int i;
 
     printf(``argc = %d$\backslash$n$\backslash$n'',argc);
     for (i=0;i<argc;++i)
       printf(``argv[%d]: %s$\backslash$n'',
         i, argv[i]);
   }

Assume it is compiled to run it as args.
So if we type:
   args f1 ``f2'' f3 4 stop! 
The output would be: 


   argc = 6
 
   argv[0] = args
   argv[1] = f1
   argv[2] = f2
   argv[3] = f3
   argv[4] = 4
   argv[5] = stop!


NOTE: $\bullet$ argv[0] is program name.
   $\bullet$ argc counts program name
   $\bullet$ Embedded `` '' are ignored.
   Blank spaces delimit end of arguments.
   Put blanks in `` '' if needed.

Pointers to a Function

 Pointer to a function are perhaps on of the more confusing uses of pointers in C. Pointers to functions are not as common as other pointer uses. However, one common use is in a passing pointers to a function as a parameter in a function call. (Yes this is getting confusing, hold on to your hats for a moment).
This is especially useful when alternative functions maybe used to perform similar tasks on data. You can pass the data and the function to be used to some control function for instance. As we will see shortly the C standard library provided some basic sorting ( qsort) and searching (bsearch) functions for free. You can easily embed your own functions.
To declare a pointer to a function do:

int (*pf) ();
This simply declares a pointer *pf to function that returns and int. No actual function is pointed to yet.
If we have a function int f() then we may simply (!!) write:

pf = &f;
For compiler prototyping to fully work it is better to have full function prototypes for the function and the pointer to a function:

int f(int);
int (*pf) (int) = &f;
Now f() returns an int and takes one int as a parameter.
You can do things like:

ans = f(5);
ans = pf(5);
which are equivalent.
The qsort standard library function is very useful function that is designed to sort an array by a key value of any type into ascending order, as long as the elements of the array are of fixed type.
qsort is prototyped in (stdlib.h):

void qsort(void *base, size_t num_elements, size_t element_size,
   int (*compare)(void const *, void  const *));
The argument base points to the array to be sorted, num_elements indicates how long the array is, element_size is the size in bytes of each array element and the final argumentcompare is a pointer to a function.
qsort calls the compare function which is user defined to compare the data when sorting. Note that qsort maintains it's data type independence by giving the comparison responsibility to the user. The compare function must return certain (integer) values according to the comparison result:
less than zero
: if first value is less than the second value
zero
: if first value is equal to the second value
greater than zero
: if first value is greater than the second value
Some quite complicated data structures can be sorted in this manner. For example, to sort the following structure by integer key:

typedef struct {
        int   key;
        struct other_data;
} Record;
We can write a compare function, record_compare:
int record\_compare(void const *a, void  const *a)
  {  return ( ((Record *)a)->key - ((Record *)b)->key );
  }
Assuming that we have an array of array_length Records suitably filled with date we can call qsort like this:

qsort( array, arraylength, sizeof(Record), record_compare);
Designed By Blogger Templates | Templatelib & Distributed By Blogspot Templates