1.15.1.  The Unary Operators & and *

[ fromfile: pointers.xml id: refderefoperators ]

An object (in the most general sense) is a chunk of memory that can hold data. A variable is an object with a name recognized by the compiler. A variable's name can be used as if it is the object itself. For example, if you say:

    int  x  =  5;

You can use x to stand for the integer object whose value is 5, and you can manipulate the integer object directly through the name x. For example:

++x ;  // symbol x now refers to an integer with value 6

Each object has a memory address (where its data begins). The unary & operator, also known as the address-of operator, when applied to any object, returns the memory address of that object. For example: &x returns the memory address of x.

An object that holds the memory address of another object is called a pointer. We say that the pointer points to the object at the stored memory address.

   int*  y  =  &x ;

In this example, y points to the integer x. The asterisk * following the type name int indicates that y is a pointer to int.

Here the int pointer y is initialized to the address of the int variable x. One of the powerful features of pointers is that, subject to rules that we will explore shortly, it is possible for a pointer of one type to hold the address of an object of a different (but related) type.

Zero (0), often represented by the macro NULL in C programs, is a special value that can be legally assigned to a pointer, usually when it is initialized or after it has been deleted. 0 is not the address of any object. A pointer that stores the value 0 is called a null pointer. Stroustrup recommends the use of 0 rather than the macro NULL in C++ programs.

A pointer to a simple type uses exactly the same amount of memory as a pointer to a large complicated object. That size is usually the same as sizeof(int) on that machine.

The unary * operator, also known as the dereference operator, when applied to a non-null pointer, returns the object at the address stored by the pointer.

[Warning]Warning

The symbol * is used in two different ways in connection with pointers:

  • It can serve as a type modifier, in a pointer variable definition.

  • It can be used as the dereference operator.

Example 1.30. src/pointers/pointerdemo/pointerdemo.cpp

#include <QTextStream>

int main() {
    QTextStream cout(stdout);
    int x = 4;
    int* px = 0 ;            1
    px = &x;
    cout << "x = " << x
         << " *px = " << *px 2
         << " px = " << px
         << " &px = " << &px << endl;
    x = x + 1;
    cout << "x = " << x
         << " *px = " << *px
         << " px = " << px << endl;
    *px = *px + 1;
    cout << "x = " << x
         << " *px = " << *px
         << " px = " << px << endl;
    return 0;
}


Output:

OOP> ./pointerdemo
x = 4 *px = 4 px = 0xbffff514 &px = 0xbffff510
x = 5 *px = 5 px = 0xbffff514
x = 6 *px = 6 px = 0xbffff514
OOP>


1

Type modifier

2

Unary dereference operator

<include src="src/pointers/pointerdemo/pointerdemo.cpp" href="src/pointers/pointerdemo/pointerdemo.cpp" id="pointerdemo1" mode="cpp"/>


When Example 1.30 is run at different times, or on different machines, the memory addresses are likely to be different.

The variable x accesses its data directly but the variable px accesses the same data indirectly. This is why the word indirection is often used to characterize the process of accessing data through a pointer. The relationship between the two variables, x and px, is illustrated in Figure 1.4.

Figure 1.4.  Pointer Demo

Pointer Demo

Because whitespace is ignored by the compiler, the location of whitespace can help or confuse the reader. To improve readability and maintainability of C++ code that contains pointer declarations, we recommend that

 T* ptr;

This declaration is unambiguous: ptr is a pointer to type T.