CS170 Lab: C++ Pointers

Highlights of this lab:

In this lab,  you will:

Lab Exercise:

Click the little computer above for a detailed description.

Definition of a Pointer.

Pointers are a type of variable that allow you to specify the address of a variable. They provide a convenient means of passing arguments to functions and for referring to more complex datatypes such as structures. They are also essential if you want to use dynamic data in the free store area. (That was a free look ahead to the dynamic data topic covered later in these notes.)

You won't always know the specific value in a pointer, but you won't care as long as it contains the address of the variable you are after. You need to declare and initialize pointers just as you would other variables, but there are special operators that you need to use.

Pointer Operators.

Here is a table showing the special characters used in C++ to declare and use pointers.

dereference operator,
indirection operator
This is used to declare a variable as a pointer.
It is also used when you want to access the value pointed to by the pointer variable.
reference operator,
address-of operator
Use before a variable to indicate that you mean the address of that variable. You'll often see this in a function header where the parameter list is given.
member selection operatorThis is used to refer to members of structures

Simple Pointer Use.

We'd better look at some examples to make this clear.

First, we'll declare two ordinary integers, and also pointers to those integers.

int 	alpha 	= 5;
int 	beta 	= 20;
int*	alphaPtr	=  α
int*	betaPtr	=  β
The characters Ptr in the pointer variable name have no special significance. They are simply a memory aid for the programmer. Let's look more closely at one of the pointer declarations.
int*	alphaPtr	=  α
The first part int*, tells the compiler to declare a pointer for integers. alphaPtr will be the name of that pointer. In the last part of that statement, α specifies that the address of the variable alpha is what should be assigned to the pointer variable.

An aside here: It is also permissable to position the asterisk closer to the pointer variable name,
i.e. int  *alphaPtr.   However the convention seems to be moving towards placing the asterisk closer to the datatype.

Try to visualize memory after these declarations, thinking of the pointer variable as not having a particular value, simply links to the variables to which they had been assigned.

Now let's look at a trivial example of how to access this data.
*alphaPtr += 5;
*betaPtr += 5;

After these statements, it is only the contents of the alpha and beta variables that would be changed.

You might say, "What's the big deal here? I could just as easily have written this:"
alpha += 5;
beta += 5;

True, but typically pointers aren't used in such a simple manner. We just showed this to illustrate the use of pointer syntax.

Using Pointers to Pass Parameters by Reference.

A more realistic example of pointer use is to see how pointers can be used in passing parameters to a function by reference. In other words, you want to pass the addresses of the data to a function rather than the values of the data.

Let's look at both pass by value and pass by reference to make sure we understand the difference. There is a little example in the C++ Syntax Web Pages (the section on Pointers) that illustrates how parameters are passed by value. Here's what that looks like:

	int a = 5;
	int b = 9;
	exchange(a,b);    // main pgm function call
	void exchange(int x, int y)	// pass by value
	    int temp;
	    temp = x;
	    x = y;
 	    y = temp;
Simple, direct - right? Well yes, but the values of a and b in the main program have not been changed! If that is what you really wanted to do, you should have used pointers to pass the parameters by reference.

To do this, you need to change the function prototype and header to
void exchange(int & x, int & y)
Here is what the whole program looks like.

#include <string.h>
#include <iostream>
     using namespace std;

void exchange (int& x, int& y);

     int main ()
	int a = 5;
        int b = 9;

        cout << "This program exchanges 2 values." << endl;
        cout << "Values before the exchange:" << endl;
	cout << "a= " << a << " b= " << b << endl;

        exchange(a, b);  // code that calls the function

        cout << "Values after the exchange:" << endl;
	cout << "a= " << a << " b= " << b << endl;

// function for passing by reference 

     void exchange (int& x, int& y)
        int temp;

        temp = x;
        x = y;
        y = temp;
     } // end exchange

Now, when the function is executed, the values of a and b will be changed in the main program. Next we'll look at how pointers are used with C++ structures.

Pointers and Structures

Let's start here by looking at an example of the structure STUDENT.
	struct STUDENT	// define the structure
	    char name[20];
	    int id;
	    int mark[3];
	void main()
	    STUDENT stu;	// declare an instance of the structure
You could simply pass the address of that instance directly to a function by coding:
You could also add a pointer declaration to reference that instance.
	STUDENT *    stuPtr  = &stu;
The general syntax to declare a pointer and associate it with the instance of a structure is this:
	structure_name  *    pointer_name   =  & instance_name;
Now, using this pointer to reference the structure instance, we could write:
	(*stuPtr).id   =  1999;
The *, (the indirection operator), tells the compiler to use what stuPtr is pointing to. The parentheses are necessary because you want the compiler to evaluate the address in stuPtr before that value is connected to the id member delimeted by the dot operator. This is because the dot operator normally takes precedence over the indirection operator. (Remember order of precedence and order of evaluation in an expression? If not, grab your text and review these topics.)

The syntax get awkward here though. i.e. (*stuPtr).id    While that form of reference is technically correct, it is somewhat cumbersome, so C++ also allows another, easier form of reference.

	stuPtr->id = 1999;
This form eliminates the parentheses in a dot expression. We'll see more of this in the programming exercise for this week's lab exercise. The next section of these notes explains how pointers are necessary for a C++ construct called dynamic data.

Dynamic Data and Pointers.

Dynamic data items are called dynamic because they are created and deleted at run time. There are two operators used to perform these functions.
new datatype Used to allocate a dynamic variable.
e.g. int *TmpPtr = new int;
delete pointer Used to deallocate a dynamic variable.
e.g. delete TmpPtr;

The new operator is used to create dynamic data variables in the so-called free store, available in memory for this purpose. Free space is also referred to as the heap. (Even guru's have been known to let their hair down sometimes.) A couple of points to remember when you use the new statement.

  1. You can't directly name a dynamic data variable as you can other regular variables. If you can't name it, then how do you reference it? The answer is that you do this with a pointer.
  2. When the new operation is executed, it returns a pointer to the location of the variable space in the free store.
So let's look again at that example of using new.

int* TmpPtr   =  new  int;
The first part, int* TmpPtr, declares an integer pointer named tmpPtr. The second part, new int, creates a space in the free store, and returns a pointer to that space. The returned pointer is assigned to TmpPtr. This is typical of C++, i.e. you can accomplish a lot in a single line of code.

You can declare arrays in free store as well as simple variables.
e.g. int* WeightPtr = new int [3];
To use this dynamic array element you could code:

	WeightPtr[1] = 17;  // Note: the "*" is not needed in an array reference.

We'll see more of this in the programming exercise for this week's lab exercise. The whole idea of using dynamic data is to economize on memory space. So when you've finished with a piece of dynamic data you should release the space with the delete statement.

delete TmpPtr;
delete [] WeightPtr;
This releases space in the free store, but does not delete the pointer. Be careful here! If you try to use the pointer again, after the delete statement, you don't know what address will be in the pointer. Beware the dreaded segmentation fault, core dump! (See the next section for details.)

To safeguard an inadvertent overwrite of a critical area in memory, it is advisable to set pointers to NULL after you delete the associated dynamic data space. e.g.

TmpPtr = NULL;
WeightPtr = NULL;

Pointers Running Wild!!

You need to be careful when you use pointers, because if you are not careful, a pointer could take on a memory address that is outside the bounds of your program space. If that happens you could see the very cryptic message:
Segmentation fault - core dump.
This is a really ugly way of punting you and your program out of computer memory. Unix guru's might have some hope of decyphering the core file which is supposed to be a dump of the contents of memory (called core way back when the earth was cooling. Yes, C is that old.)

Normal people deal with the core file more simply.

	rm   core
does the trick quite nicely. That can be a truly big file, so you don't want it hanging around taking up your disk space.

But what about the problem that caused the dump in the first place?! Well, if you're using pointers in your program, it's likely that one of them took on a bad value. Go back to your source code and look for statements that change pointer values. Remember that when you are in vi, you can search for a particular string (such as the name of a pointer) by entering: /search_string/

Lab Exercise -- C++ Pointers

Don't be disturbed by the length of the description of this particular exercise. It is not particularly hard, it is simply composed of a series of individual steps. Once you are all done, you will feel comfortable with these tools:

Now, read this description carefully as you proceed through each step.

There, that took you through a few steps to practice these new tools. If you didn't get time to finish this off during the lab period, be sure to finish it off before next week's lab. Remember you can go to CL119 during posted office hours for help. You can also email your lab instructor if you have a specific question. It's important that you master these tools in this simple exercise so that you can use them easily in the more elaborate routines you will need for class assignments.

CS Dept Home Page
CS Dept Class Files
CS170 Lab Files

This page last modified: Thursday, 06-Oct-2011 12:13:32 CST
Copyright: Department of Computer Science, University of Regina.