L-28 MCS 260 Wed 24 Oct 2001

Observe in the program below the very important difference between note that the statement double *ptr_to_pi = &pi assigns to the pointer: the * belongs to the declaration and should not be seen as a dereferencing.
/* L-28 MCS 260 Wed 24 Oct 2001 : addressing and dereferencing

Pointers allow to manipulate variables indirectly,
as show in the program below.  Since we use asin of math.h,
this program should be compiled with the option -lm.            */

#include<stdio.h>
#include<math.h>

int main(void)
{
   double pi = 3.1415;            /* very crude approximation */

/*   double *ptr_to_pi = π */       /* pointer to pi */

   double *ptr_to_pi;             /* observe the difference : */
   ptr_to_pi = π               /* no dereferencing operator here !!! */

   printf("pi = %.15lf\n", pi);

   *ptr_to_pi = 2.0l*asin(1.0l);  /* improve approximation of pi */

   printf("pi = %.15lf\n", pi);

   return 0;
}
The indirect manipulation of variables allows us to create more powerful functions :
/* L-28 MCS 260 Wed 24 Oct 2001 : call by reference 

The program below is another illustration of call by reference:
we create a function that sorts two integers in increasing order.
To bring the integers in increasing order, the function uses a
temporary variable in the swapping.                              */

void sort ( int *a, int *b );
/* on return, *a <= *b */

#include<stdio.h>

int main(void)
{
   int a,b;

   printf("Give two integers : ");
   scanf("%d %d", &a, &b);

   sort(&a,&b);

   printf("The numbers in increasing order : ");
   printf("%d %d\n", a, b);

   return 0;
}

void sort ( int *a, int *b )
{
   if (*a > *b)
   {
      int tmp = *b;      /* tmp only needed to swap */
      *b = *a;
      *a = tmp;
   }
}
The following program is a warm up for an application of pointers to void :
/* L-28 MCS 260 Wed 24 Oct 2001 : functions that return pointers

Below we give an example of a function that returns a pointer.   */

int *integer_divisor ( int n, int d );
/* returns a pointer to the integer quotient n/d */

#include<stdio.h>

int main(void)
{
   int a,b;
   int *quot;

   printf("Give an integer : ");
   scanf("%d", &a);
   printf("Give a nonzero divisor : ");
   scanf("%d", &b);

   quot = integer_divisor(a,b); 
   printf("The integer quotient : %d\n", *quot);

   return 0;
}

int *integer_divisor ( int n, int d )
{
   int iq, *ptr_iq;     /* iq is value, ptr_iq is pointer to iq */

   iq = n/d;
   ptr_iq = &iq;

   return ptr_iq;
}
With pointers to void we can circumvent the typing mechanism of C.
/* L-28 MCS 260 Wed 24 Oct 2001 : pointers to void

To illustrate pointers to void, we create a routine that can return
variables of different types.                                       */

void *generic_divisor ( int n, int d, int flag );
/* result is the integer quotient n/d, when flag = 0,
                 float   quotient n/d, when flag = 1,
                 double  quotient n/d, when flag = 2.               */

#include<stdio.h>

int main(void)
{
   int n,d;
   int *iq;
   float *fq;
   double *dq;

   printf("Give an integer : ");
   scanf("%d", &n);
   printf("Give a nonzero divisor : ");
   scanf("%d", &d);

   iq = (int *) generic_divisor(n,d,0);         /* cast void* to int* */
   printf("The integer quotient : %d\n", *iq);

   fq = (float *) generic_divisor(n,d,1);       /* cast void* to float* */
   printf("The float quotient : %f\n", *fq);

   dq = (double *) generic_divisor(n,d,2);      /* cast void* to double* */
   printf("The double quotient : %.15lf\n", *dq);

   return 0;
}

void *generic_divisor ( int n, int d, int flag )
{
   int iq, *ptr_iq;     /* iq is value, ptr_iq is pointer to iq */
   float fq, *ptr_fq;
   double dq, *ptr_dq;

   switch(flag)
   {
      case 0: iq = n/d;
              ptr_iq = &iq;
              return ptr_iq;
      case 1: fq = ((float) n)/((float) d);
              ptr_fq = &fq;
              return ptr_fq;
      case 2: dq = ((double) n)/((double) d);
              ptr_dq = &dq;
              return ptr_dq;
   } 
}