Los punteros pueden ser constantes. El compilador pondrá más
esfuerzo aún para evitar el almacenamiento y hacer expansión de
constantes cuando se trata de punteros constantes, pero estas
características parecen menos útiles en este caso.
Lo más importante es que el compilador le avisará si intenta
cambiar un puntero constante, lo que representa un buen elemento
de seguridad. Cuando se usa const
con punteros tiene dos
opciones: se pueden aplicar a lo que apunta el puntero o a la
propia dirección almacenada en el puntero. La sintaxis es un poco
confusa al principio pero se vuelve cómodo con la práctica.
El truco con la definición de un puntero, al igual que con una
definición complicada, es leerla empezando por el
identificador e ir analizando la definición hacia afuera. El
especificador const
está ligado a la cosa
«más cercana». Así que si se quiere impedir
cambios en el elemento apuntado, escribe una definición
parecida a esta:
const int* u;
Empezando por el identificador, se lee
«u
es un puntero, que apunta a un
entero constante». En este caso no se requiere
inicialización porque está diciendo que u
puede apuntar a cualquier cosa (es decir, no es constante),
pero la cosa a la que apunta no puede cambiar.
Ahora viene la parte confusa. Podría pensar que hacer el puntero
inalterable en si mismo, es decir, impedir cualquier cambio en
la dirección que contiene u
, es tan simple
como mover la palabra const
al otro lado de la
palabra int
:
int const* v;
y pensar que esto debería leerse «v
es un puntero constante a un entero». Sin embargo, la
forma de leerlo es «v
es un puntero
ordinario a un entero que es constante». Es decir, la
palabra const
se refiere de nuevo al
entero
y el efecto es el mismo que en la
definición previa. El hecho de que estas definiciones sean
equivalentes es confuso, para evitar esta confusión por parte
del lector del código, debería ceñirse a la primera forma.