Member dereferencing Operators

Member De-referencing Operators

The pointer related operator & and * are called as referening and dereferencing operators.The referencing operator (&) is a unary operator and it returns the address of its operand variable.
The dereferencing operator (*) is a unary operator that returns the value present at the specified address.
 
Consider the below program to understand use of member referencing and dereferencing operator
#include<iostream.h>
void main()
{
    int  n= 15;
    int  *ptr;
    ptr=&n;           //referencing operator
    cout<<"\nAddress of n ="<<&n;
    cout<<"\nValue in variable ptr ="<< ptr;
    cout<<"\nValue of n ="<<n;
    cout<<”\nValue using dereferencing operator=”<<*ptr;  
}

Output
Address of n=0x8fa5fff4
Value in variable ptr=0x8fa5fff4
Value of n=15
Value using dereferencing operator=15

 

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);”.