C++ pointers – reference and dereference operators

In this tutorial we take a look at pointers. For most people it will take some time to fully understand pointers.
So you have to be patient and try to make some little programs on your own. Once you master the use of pointers, you will use them everywhere. So get ready this is a long one!

Pointers basics

To better understand pointers, it sometimes helps to compare a “normal variable” with a pointer.

When a “normal variable” is declared, memory is claimed for that variable. Let’s say you declare an integer variable MYVAR. Four bytes of memory is set aside for that variable. The location in memory is known by the name MYVAR. At the machine level that location has a memory address.

A pointer differs in the way that a pointer is a variable that points to another variable. A pointer holds the memory address of that variable. That variable contains a value. Pointers are also called address variables because they contain the addresses of other variables.

Example: We have a piece of memory with a start address of 0×2000.
That piece of memory contains a value and is named MYEXAMPLE. (This is in fact a variable). We also have a pointer MYPOINT. In this case, our pointer MYPOINT contains the address 0×2000. This is the address of MYEXAMPLE so we say MYPOINT points to MYEXAMPLE. So there is the pointer and the value pointed to.
(You can use a pointer in a certain way to get the value at the address to which the pointer points).

Many novice programmers get pointers and their contents confused. So from now on every pointer starts with the extension ptr_ (for example: ptr_MYPOINT).

Initialize a pointer

To declare a pointer you have to put an * in front of its name. A pointer can be typed or un-typed. (A typed pointer points to a particular variable type such as an integer. An un-typed pointer points to any data type).

See the following example of a declaration of a typed pointer and an un-typed pointer:


	void main()
	{
		int * ptr_A;		/* A typed pointer */
		void * ptr_B;		/* A untyped pointer */
	}

Note: A void pointer cannot be directly dereferenced because it is not pointing at a specific type. (Reference and dereference is explained further down.)

Before you can use a pointer in for instance a cout statement, you have to initialize the pointer.
The following example will not initialize the pointer:


	#include<iostream>
	using namespace std;

	void main()
	{
		int *ptr_p;
		cout << *ptr_p;
	}

Note: Most compilers will give a warning when you try to compile the example, others will not. Visual Studio 2005 will give the following warning: C4700: un-initialized local variable ‘ptr_p’ used.
(But the example will/should compile without errors.)

In this example we print the value that ptr_p points to. However, we did not initialize the pointer. In this case the pointer contains a random address or 0. The result of this program is a segmentation fault, some other run-time error or the random address is printed. The meaning of a segmentation fault is that you have used a pointer that points to an invalid address. In most cases, a pointer that is not initialized or a wrong pointer address is the cause of segmentation faults.

The next example demonstrates the correct usage of pointers:


	#include<iostream>
	using namespace std;

	void main()
	{
		int x;
		int *ptr_p;

		x = 5;
		ptr_p = &x;

		cout << *ptr_p;
	}

Note: If you forget to place * (in front of the pointer) in the cout statement, you will print the address of integer x. (Try it).

Reference and dereference operators

In the example above we used ampersand sign (&). This sign is called the reference operator. If the reference operator is used you will get the “address of” a variable. In the example above we said: ptr_p = &x;. In words: store the address of the variable x in the pointer ptr_p.

We also used the asterisk sign (*) in the cout statement. This sign is called the dereference operator. If the dereference operator is used you will get the “value pointed by” a pointer. So we said: cout << *ptr_p;. In words: print (or put into the stream) the value pointed by ptr_p. (It will print the contents of integer x.)

Note: The asterisk (*) sign in the declaration of the pointer does not mean “value pointed by”, it only means that it is a pointer (it is part of its type compound specifier). It should not be confused with the dereference operator. They are simply two different things represented with the same sign.

So we can say:

  • & is the reference operator and can be read as “address of”.
  • * is the dereference operator and can be read as “value pointed by”.

Using pointers to pass values

In the example above we used an integer ‘x’ of which we stored the “address of” into a pointer ‘ptr_p’. But it is also possible to use a pointer to pass a value to a variable.

Take a look at the next example:


	#include<iostream>
	using namespace std;

	int main ()
	{
		int x;
		int * ptr_p;

		ptr_p = &x;
		*ptr_p = 5;

		cout << x;
		return 0;
	}

Note: You can see that no value is stored in x as in the previous example (x = 5 ). But the result is the same.

First we store the address of x into the pointer ptr_p. Then we say we want the value 5 stored at the address where the pointer is pointing to (in this case x).

So you can see we can use pointers to pass values to other variables.

Pointers and arrays

The C++ language allows pointer addition and subtraction. Let’s take a look at this example:


	char num[10];
	char *ptr_toarray = &num[0];

In this example we declare an array with ten elements. Then we say that the pointer *ptr_toarray must point at the first element of the array (num[0]).

Now we could do the following (note the round brackets):


	char num[10];
	char *ptr_toarray = &num[0];
	*(ptr_toarray + 2);

This is the same as num[2]. Or we can do this:


	char num[10];
	char *ptr_toarray = &num[0];
	ptr_toarray++;

So now the pointer is pointing at the second element: num[1]. (We also could write: ptr_toarray=ptr_toarray+1;)

Take a look at the different things you can do with pointers and arrays, explained by the following example:


	#include<iostream>
	using namespace std;

	int main ()
	{
		int num[5];
		int * ptr_p;

		ptr_p = num;	//ptr_p points at first element
		*ptr_p = 1;		//Store the value 1

		ptr_p++;		//Increase to second element
		*ptr_p = 2;		//Store the value 2

		ptr_p = &num[2];	//Get addres of third element
		*ptr_p = 3;		//Store the value 3

		ptr_p = num + 3;	//Goto element 4
		*ptr_p = 4;		//Store the value 4

		ptr_p = num;	//Point at first element
		*(ptr_p+4) = 5;	//First goto element 5 and then store 5

		//Now print value of each element
		for (int i=0; i<5; i++)
			cout << num[i] << '\n';
		return 0;
	}

Operator precedence

Both the increase (++) and decrease (–) operators have greater operator precedence than the dereference operator (*), but both have a special behavior when used as suffix.

Let’s take a look at an example:


	*ptr_p++;

Because ++ has greater precedence than *, this expression is equivalent to *(ptr_p++). Therefore, what it does is to increase the value of ptr_p (so it now points to the next element). You might think this but because ++ is used as post-fix the whole expression is evaluated as the value pointed by the original reference (the address the pointer pointed to before being increased).

Notice the difference with the following example:


	(*ptr_p)++

Here the value pointed by ptr_p is increased by one. The value of the pointer itself (p_ptr) is not modified.
So the only thing that is modified is what it is being pointed to by the pointer.

Another example:


	*ptr_p++ = *ptr_a++;

The increase operator (++) has a higher precedence than *. Because we use the increase operators as post-fix (instead of prefix) first the value of *ptr_a is assigned to *ptr_p. After this is done both are increased by one.

So always remember the operator precedence. Also use parentheses () in order to avoid unexpected results and confusion when reading the code.

Pointer to Pointer

It is allowed in C++ to use a pointer to point at a pointer. The last pointer may even point at data or even point at another pointer. In order to do that, we only need to add an asterisk (*) for each level of reference in their declarations. Take a look at the example:


	#include<iostream>
	using namespace std;

	int main ()
	{
		int a;
		int * ptr_b;
		int ** ptr_c;

		a = 1;
		ptr_b = &a;
		ptr_c = &ptr_b;		//Get address of ptr_b

                //print value of a  (output is 1)
		cout << a << '\n';

                //print value where pointer ptr_b points to. (output is 1)
		cout << *ptr_b << '\n';
                
                //print address of ptr_b, that we got during the
                //ptr_c = &ptr_b; statement. (output is for example 0021F7A4)
		cout << *ptr_c << '\n';
                
                //print value where ptr_c points to. Same as value of ptr_b
                //Same as value of ptr_b and integer a. (output is 1)
		cout << **ptr_c << '\n';

	return 0;
      }

Null pointer

A null pointer is a regular pointer. It only indicates that it is not pointing to a valid memory address or reference. For instance:


	int * ptr_p;
	ptr_p = 0;

Don’t confuse null pointers with void pointers. Null pointers point to “nowhere”. Void pointers are special types of pointers that can point to anything (it has no type).

Pointers to function

The C and C++ language are a “call by value” language, which means that the called function is given a copy of its arguments, and doesn’t know their addresses. (For example: myfunction(x) call is given, the value of x is passed, not its address).

This makes it impossible to change the value of x from the inside of the function (myfunction).

Note: With an array this is not a problem. If x is an array (char x[10]) then x is an address anyway.

Take a look at the following example, which will illustrate the problem:


	#include<iostream>
	using namespace std;

	void swapping(int c, int d)
	{
		int tmp;

		tmp = c;
		c = d;
		d = tmp;
		cout << "In function:\n" << c << '\n' << d << '\n';
	}

	void main()
	{
		int a,b;

		a=5;
		b=10;
		cout << "Before:\n" << a << '\n' << b << '\n';
		swapping(a,b);
		cout << "After:\n" << a << '\n' << b << '\n';
	}

In the example the values of the parameters are swapped in the function swapping. But when the function returns nothing has happened. The result is that the values are not swapped. (Try it!).

Pointers can be used to get around the “call by value” restriction. In the next example we will use pointers to correct the problem:


	#include<iostream>
	using namespace std;

	void swapping(int *ptr_c, int *ptr_d)
	{
		int tmp;

		tmp = *ptr_c;
		*ptr_c = *ptr_d;
		*ptr_d = tmp;
		cout << "In function:\n" << *ptr_c << '\n' << *ptr_d << '\n';
	}

	void main()
	{
		int a,b;

		a=5;
		b=10;
		cout << "Before:\n" << a << '\n' << b << '\n';
		swapping(&a,&b);
		cout << "After:\n" << a << '\n' << b << '\n';
	}

Note: Don’t forget to replace “swapping(a,b);” for “swapping(&a,&b);”.

That is all for this tutorial.

This entry was posted in C++ Tutorials. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site. Tweet This! Tweet This! or use to share this post with others.

There are currently 14 responses to “C++ pointers – reference and dereference operators”

Why not let us know what you think by adding your own comment!

  1. ElNillus on October 5th, 2009:

    Excellent tutorial, as a java/c# coder I’m trying to learn c++ and I had a hard time with the tutorials at cpp.com.

    thanks and keep up the good work. :)

  2. Uiop on June 1st, 2010:

    Great tutorial, helped me a lot!

  3. crazy on August 15th, 2010:

    Gr8 Tut, helped me a lot

  4. harsha on September 24th, 2010:

    covers important things in pointers. Thanks!

  5. preeti on February 26th, 2011:

    well done. nice job

  6. memoona on March 31st, 2011:

    great tutorial.

  7. sachin pune on August 23rd, 2011:

    useful tutorial……..

  8. joan on October 8th, 2011:

    In the third box, when you write:
    ptr_p = &x;

    “&” is not the “reference” operator, it’s the “address-of” operator.
    The “reference” operator does exists and is a different thing. It is when you declare, for example, a function taking a (const Foo& f) as a parameter. Or if you write int& y = x;

    The fact that these are two very different operators that work in almost opposed ways has caused me much trouble in the past, and I assume it still confuses many people.

    In the first case (Foo* y = &x;) it really returns a pointer, so for example you would use -> notation to access members.
    On the other hand, when used within the type (Foo& y = x;), it means “y” can be treated as a value, and you can use . notation to access members, even though it’s not the original variable.

  9. Somesh on October 29th, 2012:

    Very helpful

  10. Izzo on February 17th, 2013:

    Many thanks my friend.

  11. Sribanta on June 13th, 2013:

    Thanks a lot!!!!
    Very helpful for me and hope useful for others too…
    Thanks again….

  12. Josh on June 25th, 2013:

    Thankyou very much for the tutorial , i now finally understand pointers. :)

    thankyou also to joan for clearing that up.

  13. shepherd on August 25th, 2013:

    Thank you very much for the wonderful tutorial. It is really quite helpful.After having gone through your tutorial, I tried writing the following program which is not running, what could be the problem?

    #include

    using namespace std;

    int main()
    {
    int num[7];
    int *p=num;
    for(int i=0; i<7; i++)
    {
    cout<<"enter element"<>(p+1);
    }
    cout<<"entered elements are"<<endl;
    for(int i=0; i<7; i++)
    cout<<*(p+1)<<endl;
    return 0;
    }

  14. Lisongfeng on November 5th, 2013:

    Very useful and insightful!

Leave a Reply: