6. Pointers and arrays

A pointer is a variable that contains the address of the variable. Pointers are much used in C, partly because they are sometimes the only way to express a computation, and partly because they usually lead to more compact and efficient code that can be obtained in other ways. Pointers and arrays are closely related.

The main change in ANSI C is to make explicit the rules about how pointers can be manipulated, in effect mandating what good programmers already practice and good compilers already enforce ( It is said that pointers have been lumped with the goto statement as a marvelous way to create impossibe-to-understand programs). In addition, the type void * (pointer to void) replaces char * as the proper type for a generic pointer.

Figure above shows the difference between pointer (&inches) and variable (inches). So if c is a char and quit is a pointer that points to it  we could represent situation in above way.

The unary operator & gives the address of an object, so the statement:

c = &quit

assigns the address of quit to the variable c and it is said to “point to”  quit. The & operator only applies to objects in memory. It cannot be applied to expressions, constants, or register values.

The unary operator * is the indirection or dereferencing operator; when applied to pointer, it accesses the object the pointer points to.

Example of use:

int x=1, y=2, z[10];
int *ip; /* * p is a pointer to int*/
ip=&x; /* ip now a points to x*/
y=*ip; /* y is now 1, it gives the value where it points*/
*ip=0; /* x is now 0*/
ip=&z[0;] /* ip now points to z[0]*/

Shorter example:

pntr=&cat;/*pointer to a cat*/
val= *pntr;/* now value of val is 22*/
and the same result: val=cat;

Pointers and function arguments

Since C passes arguments to functions by value, there is no direct way for the called function to alter a variable in the calling function. For instance, a sorting routine might exchange two out-of-order elements with a function called swap. It is no enough to write
where the swap function is defined as

void swap(int x, int y)/*WRONG*/
  int temp;
  temp = x;

Because of call by-value, swap cannot affect the arguments a and b in the routine that called it. The function above only swaps copies of a and b.

The way to obtain the desired effect is for the calling program to pass pointers to the values to be changed:

swap(&a, &b);

void swap(int *px, int *py)/*interchange *px and *py*/
  int temp;
  temp = *px;

Pointers and arrays

The declaration    int a[10];     defines an array a of size 10, that is. a block of 10 consecutive objects named a[0], a[1], …, a[9]. The notation a[i] refers to the i-th element of the array. If pa in is a pointer to an integer, declared as  int *pa  then the assignment pa = &a[0]  set pa to point to element zero; that is, pa contains the address of a[0]. Now the assignment  x = *pa;  will copy the contents of a[0] into x.

If pa points to a particular element of an array, then by definition pa+1 points to the next element, pa+i point i elements after pa and pa-i point i elements before. Thus, if pa points to a[10],  *(pa+1)  refers to the contents of a[1], pa+i is the address of a[i], and *(pa+i) is the contents of a[i].

The correspondence between indexing and pointer arithmetic is very close. By definition, the value of a variable or expression of type array is the address of element zero of the array. Thus after the assignment  pa = &a[0];  pa and a have identical values. Since the name of an array is a synonym for the location of the initial element, the assignment pa=&a[10] can also be written as pa = a;

There is one difference between an array name and a pointer that must keep in mind. A pointer is a variable, so pa = a and pa++ are legal. But an array name is not a variable; constructions like a=pa and a++ are  illegal.

/*strlen: return length of the string*/
int strlen(char *s)
  int n;
  for (n=0; *s != '\n'; s++)
  return n;

f (&a[2]) are equal to f (a+2), both pass to the function f the address of the subarray that starts at a[2]. Within f, the parameter declaration can read f (int arr[]) { … } or f (int *arr){ … }

Multi dimensional arrays

As earlier mentioned, arrays are excellent way to store same type of data. C provides rectangular multidimensional array, although in practice they are much less used than arrays of pointers. In this section you’ll learn some of their properties.

Usage: int table_name[ i ] [ j ];/* [row] [col] */

Consider the problem of date conversion, from day of the month to day of the year and vice versa. For example, March 1 is the 60th day of a non-leap year, and 61st day of a leap year. Let us define two functions to do the conversions: day_of_year converts the month and day into the day of the year, and month_day converts the day of the year into the month and day. Since this latter function computes 2 values, the month and day arguments will be pointers:   month_da(1988, 60, &m, &d) sets m to 2 and d to 29 (February 29th).

These functions both need the same information, a table of the number of days in each month. Since the number of days per month differs for leap and non-leap years, it’s easier to separate them into 2 rows of a two-dimensional array than to keep track of what happens to February during computation.

static char daytab[2] [13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
/* day_of_year:set day of the year from month and day */
int day_of_year(int year. int month, int day)
  int i, leap;
  leap = year%4 == 0 && year%100 != 0 || year%400 == 0)
  for (i=1; idaytab[leap][i]; i++)
    yearday -= daytab[leap][i];
  *pmonth = i;
  *pday = yearday;

The array daytab has to be external to both day_of_year and month_day, so they can both use it.

Initialization of pointer arrays

Consider the problem of writing a function month_name(n), which returns a pointer to a character string containing the name of the n-th month. This is an ideal application for an internal static array. Function month_name contains a private array of character strings, and returns a pointer to the proper one when called. The syntax is similar to previous initializations:

/* month_name: returns name of n-th month */
char *name(int n)
  static char *name[] = {
    "Illegal month",
    "January", "February", "March",
    "April", "May", "June",
    "July", "August", "September", 
    "October", "November", "December"
  return (n<1 || n>12) ? name[0] : name[n]

Since the size of the array name is not specified, the compiler counts the initializers and fill in the correct number.

NOTE! Exercises for this chapter  can be found in quizzes Exercises 6 and P5-6 where  these skills will also be tested. It is also important that the student does these examples above.