2.3.3. Understanding Compound Type Declarations

Image

As we’ve seen, a variable definition consists of a base type and a list of declarators. Each declarator can relate its variable to the base type differently from the other declarators in the same definition. Thus, a single definition might define variables of different types:

// i is an int; p is a pointer to int; r is a reference to int
int i = 1024, *p = &i, &r = i;


Image Warning

Many programmers are confused by the interaction between the base type and the type modification that may be part of a declarator.


Defining Multiple Variables
Image

It is a common misconception to think that the type modifier (* or &) applies to all the variables defined in a single statement. Part of the problem arises because we can put whitespace between the type modifier and the name being declared:

int* p;  // legal but might be misleading

We say that this definition might be misleading because it suggests that int* is the type of each variable declared in that statement. Despite appearances, the base type of this declaration is int, not int*. The * modifies the type of p. It says nothing about any other objects that might be declared in the same statement:

int* p1, p2; // p1 is a pointer to int; p2 is an int

There are two common styles used to define multiple variables with pointer or reference type. The first places the type modifier adjacent to the identifier:

int *p1, *p2; // both p1 and p2 are pointers to int

This style emphasizes that the variable has the indicated compound type.

The second places the type modifier with the type but defines only one variable per statement:

int* p1;       // p1 is a pointer to int
int* p2;       // p2 is a pointer to int

This style emphasizes that the declaration defines a compound type.


Image Tip

There is no single right way to define pointers or references. The important thing is to choose a style and use it consistently.


In this book we use the first style and place the * (or the &) with the variable name.

Pointers to Pointers

In general, there are no limits to how many type modifiers can be applied to a declarator. When there is more than one modifier, they combine in ways that are logical but not always obvious. As one example, consider a pointer. A pointer is an object in memory, so like any object it has an address. Therefore, we can store the address of a pointer in another pointer.

We indicate each pointer level by its own *. That is, we write ** for a pointer to a pointer, *** for a pointer to a pointer to a pointer, and so on:

int ival = 1024;
int *pi = &ival;    // pi points to an int
int **ppi = π    // ppi points to a pointer to an int

Here pi is a pointer to an int and ppi is a pointer to a pointer to an int. We might represent these objects as

Image

Just as dereferencing a pointer to an int yields an int, dereferencing a pointer to a pointer yields a pointer. To access the underlying object, we must dereference the original pointer twice:

cout << "The value of ival "
     << "direct value: " << ival << " "
     << "indirect value: " << *pi << " "
     << "doubly indirect value: " << **ppi
     << endl;

This program prints the value of ival three different ways: first, directly; then, through the pointer to int in pi; and finally, by dereferencing ppi twice to get to the underlying value in ival.

References to Pointers

A reference is not an object. Hence, we may not have a pointer to a reference. However, because a pointer is an object, we can define a reference to a pointer:

int i = 42;
int *p;        // p is a pointer to int
int *&r = p;   // r is a reference to the pointer p
r = &i; //  r refers to a pointer; assigning &i to r makes p point to i
*r = 0; //  dereferencing r yields i, the object to which p points; changes i to 0

The easiest way to understand the type of r is to read the definition right to left. The symbol closest to the name of the variable (in this case the & in &r) is the one that has the most immediate effect on the variable’s type. Thus, we know that r is a reference. The rest of the declarator determines the type to which r refers. The next symbol, * in this case, says that the type r refers to is a pointer type. Finally, the base type of the declaration says that r is a reference to a pointer to an int.


Image Tip

It can be easier to understand complicated pointer or reference declarations if you read them from right to left.



Exercises Section 2.3.3

Exercise 2.25: Determine the types and values of each of the following variables.

(a) int* ip, i, &r = i;

(b) int i, *ip = 0;

(c) int* ip, ip2;


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.235.219