CS202 Computer Science II
FAQ Newsboard  Telnet Email TA Lectures Assignments Man pages Help

Pointers

Chapter 7 in textbook....

Pointers are used everywhere in C/C++, and if you have a good understanding of them C/C++ should not pose a problem. If, however, you have never seen pointers before, or feel uncomfortable with them, you may want to schedule an appointment to talk to me. C/C++ pointers are basically the same as Pascal pointers except they are used much more freely in C/C++.

C++ uses pointers in three main ways. First, they are used to create dynamic data structures: data structures built up from blocks of memory allocated from the heap at run-time. This is the only visible way that Pascal uses pointers. Second, C++ uses pointers to handle variable parameters passed to functions. And third, pointers in C++ provide an alternative means of accessing information stored in arrays, which is especially valuable when you work with strings. There is an intimate link between arrays and pointers in C/C++.

In many cases, C/C++ programmers use pointers because they make the code slightly more efficient. Sometimes, however, they simply seem to make the code harder to understand. Once you have mastered the three uses of pointers in C/C++, however, you "know" C/C++ for all practical purposes.

Please note that the address of a variable is different from the value of a variable.


Consider the example code:
#include <stdio.h>
 
int main()  
{    
  int num1, num2j;    

  int *ptr;  /* declaring a pointer to an integer */ 

  ptr = &num1;    /* The address-of operator */
  *ptr = 5;       /* Dereferencing a pointer */
  num2 = num1;    

  cout <<  num1 <<  num2 << *ptr ;
} 

Declaring a pointer

The int *ptr declares a pointer. It asks the compiler to declare a variable p that is a pointer to an integer. The * indicates that a pointer is being declared rather than a normal variable. You can create a pointer to anything: a float, a char, and so on. You can even create a pointer to a pointer to a data-type. So for example: float *fptr would declare a pointer to a real number, and char * charptr declares a pointer to a character.

Note: We must associate a pointer to a particular type: You can't assign the address of a char to an int, for instance.

The Address operator: &

The & unary operator generates the memory address of the variable operand. For example: & num1 refers to the address of the variable num1. Thus ptr = &num1 assigns the address of the integer variable num1 to the pointer variable, ptr. So the integer pointer variable, ptr, contains the memory address of the integer variable num1 after ptr = &num1. Suppose ptr is at memory address 500, while num1 and num2 are memory addresses 600 and 604 respectively.

Dereferencing a pointer

If you want to access the value of the variable at the location pointed to by a pointer, you have to use the * operator. The * operator can be used in many ways, 1) multiplication, 2) declaring a pointer, and 3) derefencing a pointer. Thus *iptr = 5 sets the contents of the location pointed to by iptr to be 5. Since iptr points to num1, num1 gets the value 5 assigned to it.

You cannot use a pointer before you make it point to a variable. For example:

   int *iptr;
   *iptr = 5;
can cause your program to crash, since you are trying to put the value 5 at the memory location pointed to by iptr; and iptr doesn't point anywhere.
   int number, *iptr;

   iptr = &number;
   *iptr = 30;
is perfectly legal.

Here are some things you can and cannot do with pointers. The pictures in this section provide example values for the memory locations at which variables are stored. These values are for helping your understanding only. In practice, we seldom deal with memory addresses values, dealing instead with pointer variables.

int main(void)
{
...
  int num1, num2;
  int *ip1, *ip2;

  ip1 = 20;   /* shouldn't do this */
  *ip1 = 20;  /* will cause a run time error */

  num1 = 45;
  ip1 = &num1;
  ip2 = ip1;   /* ip1 and ip2 both point to the same location */
  cout	<< "The location pointed to by ip2 contains "
	<< *ip2;
  cout	<< "The location pointed to by ip1 contains "
	<< *ip1;
  cout	<< " num1 contains "
	<< num1;
...
}
The first statement tries to make ip1 point to the memory address 20. Since we don't know what memory addresses our variables are stored at, trying to assign some number to a pointer variable is not recommended. The second statement tries to store the value 20 at memory location 20 (the location pointed to be ip1). Since the memory location probably does not belong to our program, the statement will cause a segmentation fault and crash our executable.

If we do things right, and let ip1 point to a variable (num1), assigning ip2 the current value of ip1, makes both ip2 and ip1 point to num1. All three print statements will therefore print the same value.

Another example :

int main(void)
{
  float rel1, rel2, *fp1, *fp2;

  fp2 = &rel1 ;  
  rel1 = 50.7;  /*  picture this */
  cout	<<	"The location pointed to by fp2 contains "
	<<	*fp2;
}

Back to the Top of this page

Consider the following program that uses pointers to pointers, pointers to pointers to pointers, and pointers to pointers to pointers to pointers!

/* Program 7-6 : A Multiple Addressing Scheme */

#include <iostream.h>

int main(void)
{
   int that = 15;
   int *this1, **this2, ***this3, ****this4;

   this1 = & that;
   this2 = & this1;
   this3 = & this2;
   this4 = & this3;

   cout << "The value of ****this4 is: "
	<< ****this4;
   cout << "The value of ****this4 is: "
	<< ***this3;
   cout << "The value of ****this4 is: "
	<< **this2;
   cout << "The value of ****this4 is: "
	<< *this1;


   return 0;
}
this4 points to this3 which points to this2 which points to this1 which points to that. this4 is a pointer to (a pointer to a pointer to a pointer to an integer). To get to the integer value stored in that you need to do four (4) dereferences! Here is a picture.


Back to the Top of this page

Here's another way of writing the swap function that we used in our sort code. In other words we can pass parameters by reference using pointers in addition to doing it the way we have been doing (declaring function paramters with type & variable-name). The invoking function would invoke swap with pointers to the integers whose values are to be swapped. For example, if we wanted to swap the values of two integer variables num1 and num2 we could invoke swap() as follows:

int main(void)
{
  int num1, num2;

  num1 = 5;
  num2 = 9;

  swap(&num1, &num2);
  cout	<< " num1 = " << num1 
	<< " num2 = " << num2;

}
and swap() would work with these pointers and change the values pointed to by the pointers without changing the values of the pointers themselves. The pointers are passed by valuu, but we can access the contents of the locations pointed to by the pointers by reference through the copied pointers.
void swap (int *ip1, int *ip2)
{
   int tmp;
   
   tmp = *ip1;
   *ip1 = *ip2;
   *ip2 = tmp;
}
Thus although we are not changing the values of ip1 and ip2, we are changing the values of the locations pointed to by ip1 and ip2. This picture will help visualize what is going on with the local copies of ip1 and ip2 and the values in num1 and num2 in main().

If we want to use swap() with our selsrt function it would be invoked as swap(&vec[i], &vec[maxIndx]) to do the swapping of elements that are in the wrong order.

Back to the Top of this page

Passing an array is just a special case of passing pointers. When you pass an array name in C/C++ you are actually passing in the address of the first element of the array. That is, you are passing a pointer to the beginning of the array. Thus cout << array[0]; is the same as cout << *array ; if you had declared an int array[10] and initialized it.


Back to the Top of this page