Department of Engineering

IT Services

C++ Pointers and References

Pointers

Let's start with a simple line of code, looking behind the scenes a little. The following line

  int i;

creates an integer called i. More formally, it creates a variable called i of type int. This variable has to be stored somewhere in memory. Let's say that it's stored starting at memory location 1000. The diagram shows the situation. Note that the box is empty. That's not the case in reality. Though i hasn't been given a value (and there's no default value used by C++) the bytes will have some random values. After continuing with

  i=7;

we'd have the situation shown in the 2nd diagram. Now let's do

  int *p;

This creates a variable called p of type pointer-to-int. Like the i we initially created, it's stored somewhere (let's say at memory location 2000) and it's not initialised to a value. Let's set it now.

  p=1000;

The value it's been set to isn't arbitrary - it's the location of i. p now "points to" i. If we want to print what p points to (rather than p itself) , we can do

  cout << *p << endl;

It will print what's at memory location 1000 - namely 7. Note the effect of the "*" operator in this context - followed by a memory location, it will return what's stored at that location. This operation is called dereferencing.

To work with pointers you need to be able to find out where variables are stored. The & operator does this, so in the example above, rather than p=1000; we could do

  p=&i;

Note that in this context, "&" and "*" are inverse operations - given a variable, "&" will find its location; given a location, "*" will find what value's there.

References

C++ also offers "references". Again, we'll start with a simple code fragment.

  int i=5;
  int &r=i;

The "&" symbol is being used again, but now it's doing something different. r is of type "reference to an int" - essentially, it's an alias for the variable i. If we continue with

 cout << r << endl;
 int i=7;
 cout << r << endl;

the output will be

5 7

References or Pointers?

There's often a choice of using pointers or references when dealing with "call by reference". Suppose we want to write a function that will triple the value of a given variable. We could try the following -

#include <iostream>
using namespace std;

void triple(int i) {
  i=i*3;
  cout << "in triple, i is " << i << endl; 
  cout << "In triple, i is stored at memory location " << &i << endl;
}

int main()
{
int i=3;
  cout << "In main, i is " << i <<  endl;
  triple(i);
  cout << "In main, i is now " << i <<  endl;
  cout << "In main, i is stored at memory location " << &i << endl;
}

But that doesn't work as we wanted (run it if you have doubts). The problem is that the triple function is never told where main's i is stored so it can't change its value. The i in triple is a different i which only exists in the triple function. It's stored in a different place to main's i. That the 2 variables have the same name is a coincidence. The only link between the 2 variables is that when triple is called, triple's i gets its initial value from main's i - i is being passed "by value". We can solve that problem in 2 ways -

// Using Pointers
#include <iostream>
using namespace std;

// the next line tells "triple" to expect a pointer to an integer
void triple(int *i) {  // this line has changed
  *i=*i*3; // this line has changed
}

int main()
{
int i=3;
   cout << "i is " << i <<  endl;
   triple(&i); // this line has changed too
   cout << "i is now " << i <<  endl;
}
// Using References
#include <iostream>
using namespace std;

// the next line of code says that i is being passed by reference.
void triple(int& i) {  // this line has changed
  i=i*3; // here i is an alias for main's i
}

int main()
{
int i=3;
   cout << "i is " << i <<  endl;
   triple(i);
   cout << "i is now " << i <<  endl;
}

Both methods work, but which is preferable? A commonly seen guideline is "use references if you can, and pointers if you must". Looking at these side-by-side examples, the version that uses references is less cluttered (in particular, "i=i*3;" is much easier on the eye than "*i=*i*3;"), but some people think that the version using pointers shows what's actually happening - seen in isolation, the "i=i*3;" line from the references example looks like it's dealing with a local variable, not a variable in another function.

One advantage of using references is that the peril of "dangling pointers" is (mostly) avoided. In the earlier example when we created a pointer using

  int *p;

p wasn't set to a value. Perhaps it might initially contain the value 0. If we tried to do

  cout << *p << endl;

we'd be asking C++ to print what's at memory location 0. Even trying to access memory location 0 is enough to crash the program. References avoid that risk. When you create a reference you have to state the variable that's being referenced - the following is illegal.

  int &r;

See also

For further information see

On the CUED central sytem we've installed the free program "c++decl" which you may find useful when trying to understand C++ declarations. Here are some examples of use, showing the output of the "c++decl" program -

  • c++decl explain "int& r;"
    declare r as reference to int
  • c++decl explain "int* r[];"
    declare r as array of pointer to int
  • c++decl declare "r as array of pointer to int"
    int *r[]