CS115 Lab: C++ Pointers


Highlights of this lab:

In this lab,  you will:

Lab Exercise:


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;

Click here to download a simple pointer program.


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. Here is a little example that illustrates how parameters are passed by value. Here's what that looks like:

	int a = 5;
	int b = 9;
	swap(a,b);    // main pgm function call
	...
	void swap(int x, int y)	// pass by value
	{
	    int temp;
	    temp = x;
	    x = y;
 	    y = temp;
	    return;
	}
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 pass by reference.

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

//Filename: swap.cpp

#include <string.h>
#include <iostream>

using namespace std;

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

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

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

   swap(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 swap (int& x, int& y)
{
   int temp;

   temp = x;
   x = y;
   y = temp;
   return;
} // end swap

Now, when the function is executed, the values of a and b will be changed in the main program.

(Click to download swap.cpp)

Let us reimplement swap with pointers. This is how pass by reference was done in traditional C (before C++)
// function for passing by reference using pointers
void swap (int* x, int* y)
{
   int temp;

   temp = *x;
   *x = *y;
   *y = temp;
   return;
} // end swap

Why do we have to put the * in front of x and y when we are doing assignment?

Note that our call from main will be:

swap (&a, &b);

It may seem like we have added a level of complexity to pass by reference, but trust me, this information will help you if you ever work with traditional C functions (found in CS330).

Next, we will look at how pointers are used with C++ structures.

Pointers and Structures

Let's start here by looking at an example of a structure called Student.
	struct Student	// define the structure
	{
	    string name;
	    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:
	function_name(&stu);
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 gurus 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 (or nullptr) after you delete the associated dynamic data space. e.g.

tmpPtr = NULL; //or tmpPtr = nullptr
weightPtr = NULL; //or weightPtr = nullptr

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 gurus 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 emacs, you can search for a particular string (such as the name of a pointer) by entering: C-s search_string


Lab Exercise:


This page last modified:
Monday, 14-Mar-2016 17:14:55 CST

CS Dept Home Page
CS Dept Class Files
CS115 Lab Files

Copyright: Department of Computer Science, University of Regina.