const
As with references, we can define pointers that point to either const
or nonconst
types. Like a reference to const
, a pointer to const
(§ 2.4.1, p. 61) may not be used to change the object to which the pointer points. We may store the address of a const
object only in a pointer to const
:
const double pi = 3.14; // pi is const; its value may not be changed
double *ptr = π // error: ptr is a plain pointer
const double *cptr = π // ok: cptr may point to a double that is const
*cptr = 42; // error: cannot assign to *cptr
In § 2.3.2 (p. 52) we noted that there are two exceptions to the rule that the types of a pointer and the object to which it points must match. The first exception is that we can use a pointer to const
to point to a nonconst
object:
double dval = 3.14; // dval is a double; its value can be changed
cptr = &dval; // ok: but can't change dval through cptr
Like a reference to const
, a pointer to const
says nothing about whether the object to which the pointer points is const
. Defining a pointer as a pointer to const
affects only what we can do with the pointer. It is important to remember that there is no guarantee that an object pointed to by a pointer to const
won’t change.
It may be helpful to think of pointers and references to const
as pointers or references “that think they point or refer to const
.”
const
PointersUnlike references, pointers are objects. Hence, as with any other object type, we can have a pointer that is itself const
. Like any other const
object, a const
pointer must be initialized, and once initialized, its value (i.e., the address that it holds) may not be changed. We indicate that the pointer is const
by putting the const
after the *
. This placement indicates that it is the pointer, not the pointed-to type, that is const
:
int errNumb = 0;
int *const curErr = &errNumb; // curErr will always point to errNumb
const double pi = 3.14159;
const double *const pip = π // pip is a const pointer to a const object
As we saw in § 2.3.3 (p. 58), the easiest way to understand these declarations is to read them from right to left. In this case, the symbol closest to curErr
is const
, which means that curErr
itself will be a const
object. The type of that object is formed from the rest of the declarator. The next symbol in the declarator is *
, which means that curErr
is a const
pointer. Finally, the base type of the declaration completes the type of curErr
, which is a const
pointer to an object of type int
. Similarly, pip
is a const
pointer to an object of type const double
.
The fact that a pointer is itself const
says nothing about whether we can use the pointer to change the underlying object. Whether we can change that object depends entirely on the type to which the pointer points. For example, pip
is a const
pointer to const
. Neither the value of the object addressed by pip
nor the address stored in pip
can be changed. On the other hand, curErr
addresses a plain, nonconst int
. We can use curErr
to change the value of errNumb
:
*pip = 2.72; // error: pip is a pointer to const
// if the object to which curErr points (i.e., errNumb) is nonzero
if (*curErr) {
errorHandler();
*curErr = 0; // ok: reset the value of the object to which curErr is bound
}