Pointer Basics in C++

A pointer variable holds the memory address. Through the pointer, you can use the Point dereference operator * to access the actual value at a specific memory location.

Pointer variables, simply called pointers, are declared to hold memory addresses as their values. Normally, a variable contains a data value—e.g., an integer, a floating-point value, and a char­acter. However, a pointer contains the memory address of a variable that in turn contains a data value. As shown in Figure 11.1, pointer pCount contains the memory address for variable count.

Each byte of memory has a unique address. A variable’s address is the address of the first byte allocated to that variable. Suppose three variables count, status, and letter are declared as follows:

int count = 5;

short status = 2;

char letter = ‘A’;

string s(“ABC”);

As shown in Figure 11.1, variable count is declared as an int type which contains four bytes, variable status is declared as a short type which contains two bytes, and variable letter is declared as a char type which contains one byte. Note that the ASCII code for ‘A’ is hex 55. Var­iable s is declared as a stri ng type whose memory size may change, depending on the number of the characters in the string, but the memory address for the string is fixed, once string is declared.

Like any other variables, pointers must be declared before they can be used. To declare a pointer, use the following syntax:

dataType* pVarName;

Each variable being declared as a pointer must be preceded by an asterisk (*). For example, the following statements declare pointers named pCount, pStatus, and pLetter, which can point to an int variable, a short variable, a char variable, and a string, respectively.

int* pCount;

short* pStatus;

char* pLetter;

string* pString;

You can now assign the address of a variable to a pointer. For example, the following code assigns the address of variable count to pCount:

pCount = &count;

The ampersand (&) symbol is called the address operator when placed in front of a variable. It is a unary operator that returns the variable’s address. So, you may pronounce &count as the address of count.

Line 6 declares a variable named count with an initial value 5. Line 7 declares a pointer variable named pCount and initialized with the address of variable count. Figure 11.1 shows the relationship between count and pCount.

Listing 11.1 gives a complete example that demonstrates the use of pointers

Listing 11.1 TestPointer.cpp

1 #include <iostream>
2
using namespace std;
3
4
int main()
5 {
6   
int count = 5;
7   
int* pCount = &count;

8
9    cout <<
“The value of count is ” << count << endl;
10   cout <<
“The address of count is ” << &count << endl;
11   cout <<
“The address of count is ” << pCount << endl;
12   cout <<
“The value of count is ” << *pCount << endl;
13
14   
return 0;
15 }

Line 6 declares a variable named count with an initial value 5. Line 7 declares a pointer variable named pCount and initialized with the address of variable count. Figure 11.1 shows the relationship between count and pCount.

A pointer can be initialized when it is declared or by using an assignment statement. How­ever, if you assign an address to a pointer, the syntax is

pCount = &count; // Correct

rather than

*pCount = &count; // Wrong

Line 10 displays the address of count using &count. Line 11 displays the value stored in pCount, which is same as &count. The value stored in count is retrieved directly from count in line 9 and indirectly through a pointer variable using *pCount in line 12.

Referencing a value through a pointer is often called indirection. The syntax for referenc­ing a value from a pointer is

*pointer

For example, you can increase count using

count++; // Direct reference

or

(*pCount)++; // Indirect reference

The asterisk (*) used in the preceding statement is known as the indirection operator or dereference operator (dereference means indirect reference). When a pointer is dereferenced, the value at the address stored in the pointer is retrieved. You may pronounce *pCount as the value indirectly pointed by pCount, or simply pointed by pCount.

The following points on pointers are worth noting:

  • The asterisk (*) can be used in three different ways in C++:
  • As a multiplication operator, such as

double area = radius * radius * 3.14159;

  • To declare a pointer variable, such as

int* pCount = &count;

  • As the dereference operator, such as

(*pCount)++;

Don’t worry. The compiler can tell what the symbol * is used for in a program.

  • A pointer variable is declared with a type such as i nt or doubl e. You have to assign the address of the variable of the same type. It is a syntax error if the type of the vari­able does not match the type of the pointer. For example, the following code is wrong:

int area = 1;

double* pArea = &area; // Wrong

You can assign a pointer to another pointer of the same type, but cannot assign a pointer to a nonpointer variable. For example, the following code is wrong:

int area = 1;

int* pArea = &area;

int i = pArea; // Wrong

  • Pointers are variables. So, the naming conventions for variables are applied to point­ers. So far, we have named pointers with prefix p, such as pCount and pArea. How­ever, it is impossible to enforce this convention. Soon you will realize that an array name is actually a pointer.
  • Like a local variable, a local pointer is assigned an arbitrary value if you don’t initialize it. A pointer may be initialized to 0, which is a special value to indicate that the pointer points to nothing. To prevent errors, you should always initialize pointers. Dereferenc­ing a pointer that is not initialized could cause a fatal runtime error or it could acciden­tally modify important data. A number of C++ libraries including <iostream> define NULL as a constant with value 0. It is more descriptive to use NULL than 0.

Suppose pX and pY are two pointer variables for variables x and y, as shown in Figure 11.2. To understand the relationships between the variables and their pointers, let us examine the effect of assigning pY to pX and *pY to *pX.

The statement pX = pY assigns the content of pY to pX. The content of pY is the address of variable y. So, after this assignment, pX and pY contain the same content, as pictured in Figure 11.2a.

Now consider *pX = *pY. With the asterisk symbol in front of pX and pY, you are deal­ing with the variables pointed by pX and pY. *pX refers to the contents in x and *pY refers to the contents in y. So the statement *pX = *pY assigns 6 to *pX, as pictured in Figure 11.2b. You can declare an int pointer using the syntax

int* p;

or

int *p;

or

int * p;

All these are equivalent. Which one is better is a matter of personal preference. This book uses the style int* p for declaring a pointer for two reasons:

  1. int* p clearly separates the type int* from the identifier p. p is of the type int*, not of the type int.

  1. Later in the book, you will see that a function may return a pointer. It is more intuitive to write the function header as

typeName* functionName(parameterList);

rather than

typeName *functionName(parameterList);

One drawback of using the int* p style syntax is that it may lead to a mistake like this:

int* p1, p2;

This line seems as if it declares two pointers, but it is actually same as

int *p1, p2;

We recommend that you always declare a pointer variable in a single line like this:

int* p1; int* p2;

Source: Liang Y. Daniel (2013), Introduction to programming with C++, Pearson; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *