calificador const para punteros a punteros

Me cuesta un poco deducir qué es const, cuando se aplica a los punteros a los punteros, etc., es decir, qué es const cuando tienes

const Foo **foo; 

¿Puedo cambiar algo aquí en ** foo? como en foo[0]->bar = 12;

Qué pasa:

  const Foo ***foo; Foo **const foo; 

Podría usar cdecl para entender lo que significa una statement en C.

 const int **foo; declare foo as pointer to pointer to const int 

por lo tanto, puede cambiar los punteros, pero no el valor al que apuntan.

 int * const * const foo; declare foo as const pointer to const pointer to int 

este, en cambio, es un puntero de cosnt, que apunta a un puntero de const, a un int no const: no puede cambiar el valor de punta, pero se puede cambiar.


C usa la Regla de las agujas del reloj / espiral , en el caso de que solo tengas modificadores en el lado izquierdo de la variable (de foo), lees cosas que van de derecha a izquierda:

 int(5) *(4) const(3) *(2) const(1) foo; 

foo es una constante (1) puntero (2) a constante (3) puntero (4) a un entero (5).

 int(6) const(5) *(4) const(3) *(2) const(1) foo; const(6) int(5) *(4) const(3) *(2) const(1) foo; // [same as above] 

En este caso foo es una constante (1) puntero (2) a constante (3) puntero (4) a una constante (5) entero (6) [o a un entero (5) que es constante (6)].

La const aplica a la expresión **foo ; por lo tanto, foo y *foo son grabables, pero **foo no lo es.

Algunos otros ejemplos:

 const Foo * const *foo; // foo is writable, *foo and **foo are not Foo * const * foo; // foo and **foo are writable, *foo is not Foo * const * const foo; // **foo is writable, foo and *foo are not const Foo * const * const foo; // none of the expressions are writable 

const Foo * * foo (o Foo const * * foo ) es un puntero a un puntero a una const Foo.

Foo * const * foo es un puntero a un puntero de const a un Foo.

Foo * * const foo es un puntero constante a un puntero a un Foo.

La forma más fácil de escribir expresiones de este tipo, creo, es que la const se aplique siempre a la izquierda. El que le diste también puede ser escrito:

 Foo const**foo; 

Aquí el const solo se aplica a lo que queda, por lo tanto Foo .

 Foo *const* foo; 

Aquí a la izquierda está Foo*

 Foo const*const* foo; 

es entonces ((Foo const)*const)* .

Cuando, a su vez, desee leer dicha expresión, intercambie la const y el tipo simple, si es necesario, para tener la const a la derecha.

En const Foo **foo , el objeto real de Foo es const. Así que puedes cambiar foo , y puedes cambiar *foo , pero no puedes cambiar **foo .

Para const Foo ***foo , puedes cambiar foo , *foo y **foo , pero no ***foo .

Para Foo **const foo , puedes cambiar *foo y **foo , pero no foo sí.

Lee tipos desde adentro hacia afuera. A partir de foo , const Foo **foo; lee * (puntero) a un * (puntero) a const Foo (un objeto Foo que no puedes modificar). Foo **const foo; lee const (no modificable) * (puntero) a * (puntero) a Foo (un objeto Foo).