¿Cuál es la diferencia entre const int *, const int * const y int const *?

1357

Siempre desordenar cómo utilizar const int*, const int * consty int const *correctamente. ¿Existe un conjunto de reglas que definan lo que puedes y no puedes hacer?

Quiero saber todo lo que se debe y no se debe hacer en términos de tareas, pasar a las funciones, etc.

MD XF
fuente
175
Puede usar la "Regla en sentido horario / espiral" para descifrar la mayoría de las declaraciones de C y C ++.
James McNellis
52
cdecl.org es un gran sitio web que traduce automáticamente las declaraciones de C por usted.
Dave Gallagher
66
@Calmarius: comience donde está / debe estar el nombre del tipo, muévase a la derecha cuando pueda, a la izquierda cuando deba hacerlo . int *(*)(char const * const). Comience a la derecha de la entre paréntesis *, entonces tenemos que mover hacia la izquierda: pointer. Fuera de los parens, podemos mover hacia la derecha: pointer to function of .... Entonces tenemos que mover hacia la izquierda: pointer to function of ... that returns pointer to int. Repita para expandir el parámetro (el ...): pointer to function of (constant pointer to constant char) that returns pointer to int. ¿Cuál sería la declaración equivalente de una línea en un lenguaje de lectura fácil como Pascal?
Mark K Cowan
1
@ MarkKCowan En Pascal sería algo así function(x:^char):^int. Hay tipos de funciones que implican un puntero a una función, por lo que no es necesario especificarla, y Pascal no impone la corrección constante. Se puede leer de izquierda a derecha.
Calmarius
55
Lo primero a la izquierda de la "constante" es lo que es constante. Si "const" es lo que está más a la izquierda, entonces lo primero a la derecha es lo que es constante.
Magdalena

Respuestas:

2209

Léalo al revés (según lo manejado en sentido horario / regla espiral ):

  • int* - puntero a int
  • int const * - puntero a const int
  • int * const - puntero constante a int
  • int const * const - puntero const a const int

Ahora el primero constpuede estar a cada lado del tipo, así que:

  • const int * == int const *
  • const int * const == int const * const

Si quieres volverte loco, puedes hacer cosas como esta:

  • int ** - puntero a puntero a int
  • int ** const - un puntero constante a un puntero a un int
  • int * const * - un puntero a un puntero constante a un int
  • int const ** - un puntero a un puntero a una constante int
  • int * const * const - un puntero constante a un puntero constante a un int
  • ...

Y para asegurarnos de que tenemos claro el significado de const:

int a = 5, b = 10, c = 15;

const int* foo;     // pointer to constant int.
foo = &a;           // assignment to where foo points to.

/* dummy statement*/
*foo = 6;           // the value of a can´t get changed through the pointer.

foo = &b;           // the pointer foo can be changed.



int *const bar = &c;  // constant pointer to int 
                      // note, you actually need to set the pointer 
                      // here because you can't change it later ;)

*bar = 16;            // the value of c can be changed through the pointer.    

/* dummy statement*/
bar = &a;             // not possible because bar is a constant pointer.           

fooes un puntero variable a un entero constante. Esto le permite cambiar lo que señala pero no el valor al que apunta. La mayoría de las veces esto se ve con cadenas de estilo C donde tiene un puntero a un const char. Puede cambiar a qué cadena apunta pero no puede cambiar el contenido de estas cadenas. Esto es importante cuando la cadena en sí está en el segmento de datos de un programa y no debe cambiarse.

bares un puntero constante o fijo a un valor que se puede cambiar. Esto es como una referencia sin el azúcar sintáctico adicional. Debido a este hecho, usualmente usaría una referencia donde usaría un T* constpuntero a menos que necesite permitir NULLpunteros.

Matt Price
fuente
482
Me gustaría agregar una regla general que pueda ayudarlo a recordar cómo descubrir si 'const' se aplica al puntero o a los datos puntiagudos: divida la declaración en el signo de asterisco, luego, si la palabra clave const aparece en la parte izquierda (como en 'const int * foo') - pertenece a datos puntiagudos, si está en la parte correcta ('int * const bar') - se trata del puntero.
Michael
14
@Michael: Felicitaciones a Michael por una regla tan simple para recordar / comprender la regla constante.
sivabudh
10
@Jeffrey: leerlo al revés funciona bien siempre que no haya paréntesis. Entonces, bueno ... use
typedefs
12
+1, aunque un mejor resumen sería: leer las declaraciones del puntero al revés , es decir, cerca de la declaración de @Michael: detener la lectura normal de izquierda a derecha en el primer asterisco.
Wolf
3
@gedamial lo hace, funciona bien, pero debe asignarlo al mismo tiempo que lo declara (porque no puede reasignar un "puntero constante"). const int x = 0; const int *const px = &x; const int *const *const p = &px;funciona bien
RastaJedi
357

Para aquellos que no conocen la regla de sentido horario / espiral: comience desde el nombre de la variable, muévase sabiamente (en este caso, retroceda) al siguiente puntero o tipo . Repita hasta que termine la expresión.

Aquí hay una demostración:

puntero a int

puntero const a int const

puntero a int const

puntero a const int

puntero constante a int

Shijing Lv
fuente
8
@ Jan el enlace para el ejemplo complejo no tiene permisos. ¿Puedes publicarlo directamente aquí o eliminar las restricciones de visualización?
R71
8
@Rog solía tener todos los permisos de acceso abierto ... No escribí el artículo y desafortunadamente no tengo permisos de acceso. Sin embargo, aquí hay una versión archivada del artículo que todavía funciona: archive.is/SsfMX
Jan Rüegg
8
El ejemplo complejo todavía es de derecha a izquierda, pero incluye resolver paréntesis de la forma en que lo haría normalmente. Todo el asunto de la espiral en el sentido de las agujas del reloj no lo hace más fácil.
Matthew leyó el
44
Último ejemplo: void (*signal(int, void (*fp)(int)))(int);de archive.is/SsfMX
naXa
3
No confíes en esta regla. Esto no es universal. Hay algunos casos donde falla.
piratea
150

Creo que todo ya está respondido aquí, pero solo quiero agregar que debes tener cuidado con typedefs! NO son solo reemplazos de texto.

Por ejemplo:

typedef char *ASTRING;
const ASTRING astring;

El tipo de astringes char * const, no const char *. Esta es una razón por la que siempre tiendo a poner consta la derecha del tipo, y nunca al principio.

Dragón Kaz
fuente
20
Y para mí esta es la razón por la que nunca escribo punteros definidos. No veo el beneficio en cosas como typedef int* PINT(supongo que es algo que proviene de las prácticas en C y muchos desarrolladores lo siguen haciendo). Genial, lo reemplacé *con un P, no acelera la escritura, además de presentar el problema que mencionas.
Mephane
1
@Mephane: puedo ver eso. Sin embargo, para mí parece un poco al revés evitar una buena característica del lenguaje para seguir usando una regla sintáctica excepcional (acerca de la colocación "constante"), en lugar de evitar usar la regla sintáctica excepcional para que pueda hacer uso de esta característica del lenguaje de manera segura .
TED
66
@Mephane PINTes, de hecho, un uso bastante tonto de un typedef, especialmente porque me hace pensar que el sistema almacena cerveza de memoria. Sin embargo, los typedef son bastante útiles para manejar punteros a funciones.
ApproachingDarknessFish
55
@KazDragon ¡GRACIAS! Sin ella, me he ensuciado con todos aquellos typedefed PVOID, LPTSTRmateria en Win32 API!
David Lee
2
@Mephane: Tuve que usar pSomething un par de veces al usar ciertas macros heredadas que se escribieron para aceptar un tipo, pero se romperían si el tipo no fuera un identificador alfanumérico único. :)
Groo
56

Como casi todo el mundo señaló:

¿Cuál es la diferencia entre const X* p, X* const py const X* const p?

Debe leer las declaraciones de puntero de derecha a izquierda.

  • const X* p significa "p apunta a una X que es constante": el objeto X no se puede cambiar a través de p.

  • X* const p significa "p es un puntero constante a una X que no es constante": no puede cambiar el puntero p, pero puede cambiar el objeto X a través de p.

  • const X* const p significa "p es un puntero constante a una X que es constante": no puede cambiar el puntero p en sí, ni puede cambiar el objeto X a través de p.

luke
fuente
3
No olvides que const X* p;== X const * p;como en"p points to an X that is const": the X object can't be changed via p.
Jesse Chisholm
Explicación simple y agradable!
Edison Lo
50
  1. Referencia constante:

    Una referencia a una variable (aquí int), que es constante. Pasamos la variable como referencia principalmente, porque las referencias son más pequeñas en tamaño que el valor real, pero hay un efecto secundario y eso es porque es como un alias de la variable real. Podemos cambiar accidentalmente la variable principal a través de nuestro acceso completo al alias, por lo que lo hacemos constante para evitar este efecto secundario.

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
    
  2. Punteros constantes

    Una vez que un puntero constante apunta a una variable, no puede apuntar a ninguna otra variable.

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
    
  3. Puntero a constante

    Un puntero a través del cual no se puede cambiar el valor de una variable que señala se conoce como puntero a constante.

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
  4. Puntero constante a una constante

    Un puntero constante a una constante es un puntero que no puede cambiar la dirección a la que apunta y tampoco puede cambiar el valor guardado en esa dirección.

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error
    
Behrooz Tabesh
fuente
20

La regla general es que la constpalabra clave se aplica a lo que la precede inmediatamente. Excepción, un comienzo se constaplica a lo que sigue.

  • const int*es lo mismo int const*y significa "puntero a int constante" .
  • const int* constes lo mismo int const* consty significa "puntero constante a int constante" .

Editar: Para lo que se debe y no se debe hacer, si esta respuesta no es suficiente, ¿podría ser más preciso sobre lo que quiere?

Un programador
fuente
19

¿Esta pregunta muestra precisamente por qué me gusta hacer las cosas de la manera que mencioné en mi pregunta ?

En resumen, creo que la forma más fácil de recordar la regla es que el "const" va después de lo que se aplica. Entonces, en su pregunta, "int const *" significa que int es constante, mientras que "int * const" significa que el puntero es constante.

Si alguien decide ponerlo al frente (por ejemplo: "const int *"), como una excepción especial en ese caso, se aplica a la cosa que está después.

A muchas personas les gusta usar esa excepción especial porque piensan que se ve mejor. No me gusta, porque es una excepción y, por lo tanto, confunde las cosas.

TED
fuente
2
Estoy desgarrado por este tema. Lógicamente tiene sentido. Sin embargo, la mayoría de los desarrolladores de c ++ escribirían const T*y se ha vuelto más natural. ¿Con qué frecuencia usas alguna vez? Por lo T* constgeneral, una referencia funcionará bien. Me mordió todo esto una vez cuando quería un boost::shared_ptr<const T>y en su lugar escribí const boost::shared_ptr<T>. Mismo problema en un contexto ligeramente diferente.
Matt Price
En realidad, uso punteros constantes con más frecuencia que las constantes. Además, debe pensar cómo va a reaccionar en presencia de punteros a punteros (etc.) Es cierto que son más raros, pero sería bueno pensar en las cosas de una manera en que pueda manejar estas situaciones con aplicación.
TED
1
La otra gran ventaja de colocar la const a la derecha del tipo es que ahora todo a la izquierda de cualquiera constes el tipo de const, y todo a su derecha es lo que en realidad es const. Toma int const * const * p;como ejemplo. No, normalmente no escribo así, esto es solo un ejemplo. Primero const: escriba int, y el int que es const es el contenido del puntero const que es el contenido de p. Segunda const: type es puntero a constint, const oblect es el contenido dep
dgnuff
18

Uso simple de const.

El uso más simple es declarar una constante con nombre. Para hacer esto, se declara una constante como si fuera una variable pero se agrega constantes. Hay que inicializarlo inmediatamente en el constructor porque, por supuesto, no se puede establecer el valor más tarde, ya que eso lo alteraría. Por ejemplo:

const int Constant1=96; 

creará una constante entera, llamada inimaginablemente Constant1, con el valor 96.

Dichas constantes son útiles para los parámetros que se usan en el programa pero que no necesitan cambiarse después de compilar el programa. Tiene una ventaja para los programadores sobre el #definecomando del preprocesador C, ya que el compilador lo comprende y lo utiliza, no solo sustituye el texto del programa por el preprocesador antes de llegar al compilador principal, por lo que los mensajes de error son mucho más útiles.

También funciona con punteros, pero hay que tener cuidado constde determinar si el puntero o lo que apunta es constante o ambos. Por ejemplo:

const int * Constant2 

declara que Constant2es un puntero variable a un entero constante y:

int const * Constant2

es una sintaxis alternativa que hace lo mismo, mientras que

int * const Constant3

declara que Constant3es un puntero constante a un entero variable y

int const * const Constant4

declara que Constant4es un puntero constante a un entero constante. Básicamente, 'const' se aplica a lo que esté a su izquierda inmediata (excepto si no hay nada allí, en cuyo caso se aplica a lo que sea su derecha inmediata).

ref: http://duramecho.com/ComputerInformation/WhyHowCppConst.html

ufukgun
fuente
9

Tenía la misma duda que tú hasta que encontré este libro del C ++ Guru Scott Meyers. Consulte el tercer elemento en este libro donde habla en detalles sobre el uso const.

Solo sigue este consejo

  1. Si la palabra constaparece a la izquierda del asterisco, lo que se señala es constante
  2. Si la palabra constaparece a la derecha del asterisco, el puntero en sí es constante
  3. Si constaparece en ambos lados, ambos son constantes
rgk
fuente
7

Es simple pero complicado. Tenga en cuenta que puede cambiar la constclasificación con cualquier tipo de datos ( int, char, float, etc.).

Veamos los siguientes ejemplos.


const int *p==> *pes de solo lectura [ pes un puntero a un entero constante]

int const *p==> *pes de solo lectura [ pes un puntero a un entero constante]


int *p const==> Declaración incorrecta . El compilador arroja un error de sintaxis.

int *const p==> pes de solo lectura [ pes un puntero constante a un entero]. Como el puntero paquí es de solo lectura, la declaración y la definición deben estar en el mismo lugar.


const int *p const ==> Declaración incorrecta . El compilador arroja un error de sintaxis.

const int const *p ==> *pes de solo lectura

const int *const p1 ==> *py pson de solo lectura [ pes un puntero constante a un entero constante]. Como el puntero paquí es de solo lectura, la declaración y la definición deben estar en el mismo lugar.


int const *p const ==> Declaración incorrecta . El compilador arroja un error de sintaxis.

int const int *p ==> Declaración incorrecta . El compilador arroja un error de sintaxis.

int const const *p ==> *pes de solo lectura y es equivalente aint const *p

int const *const p ==> *py pson de solo lectura [ pes un puntero constante a un entero constante]. Como el puntero paquí es de solo lectura, la declaración y la definición deben estar en el mismo lugar.

Abhijit Sahu
fuente
6

Hay muchos otros puntos sutiles que rodean la corrección constante en C ++. Supongo que la pregunta aquí ha sido simplemente sobre C, pero daré algunos ejemplos relacionados ya que la etiqueta es C ++:

  • A menudo pasa argumentos grandes como cadenas TYPE const &que evitan que el objeto sea modificado o copiado. Ejemplo:

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    Pero no TYPE & consttiene sentido porque las referencias son siempre constantes.

  • Siempre debe etiquetar los métodos de clase que no modifican la clase como const, de lo contrario no puede llamar al método desde una TYPE const &referencia. Ejemplo:

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • Hay situaciones comunes en las que tanto el valor de retorno como el método deben ser constantes. Ejemplo:

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    De hecho, los métodos const no deben devolver datos de clase internos como una referencia a no const.

  • Como resultado, a menudo se debe crear un método const y un método no const utilizando la sobrecarga const. Por ejemplo, si define T const& operator[] (unsigned i) const;, entonces probablemente también desee la versión no constante dada por:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik, no hay funciones const en C, las funciones que no son miembros no pueden ser const en C ++, los métodos const pueden tener efectos secundarios y el compilador no puede usar funciones const para evitar llamadas de funciones duplicadas. De hecho, incluso una simple int const &referencia podría ser testigo del cambio al valor al que se refiere en otro lugar.

Jeff Burdges
fuente
6

La sintaxis de la declaración C y C ++ ha sido repetidamente descrita como un experimento fallido por los diseñadores originales.

En su lugar, vamos a nombrar el tipo “puntero a Type”; Lo llamaré Ptr_:

template< class Type >
using Ptr_ = Type*;

Ahora Ptr_<char>es un puntero a char.

Ptr_<const char>es un puntero a const char.

Y const Ptr_<const char>es un constpuntero a const char.

Allí.

ingrese la descripción de la imagen aquí

Saludos y hth. - Alf
fuente
3
¿Tiene una cita para la primera oración?
sp2danny
@ sp2danny: Google "Experimento fallido de la sintaxis C" solo revela varias entrevistas con Bjarne Stroustrup donde expresa su opinión en esa dirección, por ejemplo, "Considero que la sintaxis del declarante C es un experimento que falló" en la entrevista de Slashdot. Por lo tanto, no tengo ninguna referencia para el reclamo sobre los puntos de vista de los diseñadores originales de C. Creo que se puede encontrar mediante un esfuerzo de investigación lo suficientemente fuerte, o tal vez refutado simplemente preguntándoles, pero creo que es mejor de la forma en que está ahora. con esa parte del reclamo, aún indeciso y probablemente cierto :)
Saludos y hth. - Alf
1
"La sintaxis de la declaración C y C ++ ha sido repetidamente descrita como un experimento fallido por los diseñadores originales". incorrecto para C, cambie su oración sobre C o proporcione algunas citas.
Stargateur el
3
@Stargateur: Aparentemente has leído los comentarios anteriores y has encontrado algo que podrías aprovechar para la pedantería. Buena suerte con tu vida. De todos modos, los veteranos como yo recuerdan mucho que no podemos probar sin dedicarnos a una investigación que lleva mucho tiempo. Podrías tomar mi palabra.
Saludos y hth. - Alf
6

Para mí, la posición de, constes decir, si aparece a la IZQUIERDA o DERECHA o tanto a la IZQUIERDA como a la DERECHA en relación con el *me ayuda a descubrir el significado real.

  1. A consta la IZQUIERDA de *indica que el objeto señalado por el puntero es un constobjeto.

  2. A consta la DERECHA de *indica que el puntero es un constpuntero.

La siguiente tabla está tomada del Stanford CS106L Standard C ++ Programming Laboratory Course Reader.

ingrese la descripción de la imagen aquí

sri
fuente
3

Esto aborda principalmente la segunda línea: mejores prácticas, tareas, parámetros de función, etc.

Práctica general. Intenta hacer todo lo constque puedas. O para decirlo de otra manera, haga todo constpara comenzar, y luego elimine exactamente el conjunto mínimo de consts necesarios para permitir que el programa funcione. Esto será de gran ayuda para lograr la corrección constante y ayudará a garantizar que no se introduzcan errores sutiles cuando las personas intentan y asignan cosas que no deben modificar.

Evite const_cast <> como la plaga. Hay uno o dos casos de uso legítimo para ello, pero son muy pocos y distantes. Si está tratando de cambiar un constobjeto, será mucho mejor encontrar a quien lo declaró consten el primer paso y discutir el asunto con ellos para llegar a un consenso sobre lo que debería suceder.

Lo que lleva muy bien a las tareas. Puede asignar a algo solo si no es constante. Si desea asignar algo que sea constante, vea más arriba. Recuerde que en las declaraciones int const *foo;y int * const bar;diferentes cosas hay constotras respuestas aquí que han cubierto ese tema admirablemente, por lo que no voy a entrar en él.

Parámetros de la función:

Pase por valor: por ejemplo void func(int param), no le importa de una forma u otra en el sitio de llamadas. Se puede argumentar que existen casos de uso para declarar la función como, void func(int const param)pero que no tiene ningún efecto en la persona que llama, solo en la función en sí misma, ya que cualquier valor que se pase no puede ser cambiado por la función durante la llamada.

Pase por referencia: por ejemplo, void func(int &param)ahora sí hace la diferencia. Como se acaba de declarar, funcestá permitido cambiar param, y cualquier sitio de llamadas debe estar listo para lidiar con las consecuencias. Cambiar la declaración a void func(int const &param)cambios en el contrato y garantiza que funcahora no puede cambiar param, lo que significa que lo que se pasa es lo que volverá a salir. Como otros han señalado, esto es muy útil para pasar de manera económica un objeto grande que no desea cambiar. Pasar una referencia es mucho más barato que pasar un objeto grande por valor.

Pasaremos por el puntero: por ejemplo, void func(int *param)y void func(int const *param)estos dos son más o menos sinónimo de sus homólogos de referencia, con la salvedad de que la función llamada ahora necesita para comprobar si hay nullptrmenos que alguna otra garantía contractual asegura funcque nunca va a recibir una nullptren param.

Artículo de opinión sobre ese tema. Probar la corrección en un caso como este es terriblemente difícil, es demasiado fácil cometer un error. Así que no se arriesgue, y siempre verifique los parámetros del puntero nullptr. Se ahorrará dolor y sufrimiento y será difícil encontrar errores a largo plazo. Y en cuanto al costo del cheque, es muy barato, y en los casos en que el análisis estático integrado en el compilador puede administrarlo, el optimizador lo eludirá de todos modos. Active la Generación de código de tiempo de enlace para MSVC, o WOPR (creo) para GCC, y obtendrá todo el programa, es decir, incluso en llamadas de función que cruzan el límite del módulo de código fuente.

Al final del día, todo lo anterior hace un caso muy sólido para preferir siempre referencias a punteros. Son más seguros en todos los aspectos.

dgnuff
fuente
3

La constante con int en ambos lados hará que el puntero a int constante :

const int *ptr=&i;

o:

int const *ptr=&i;

constafter *hará un puntero constante a int :

int *const ptr=&i;

En este caso, todos estos son punteros a enteros constantes , pero ninguno de estos son punteros constantes:

 const int *ptr1=&i, *ptr2=&j;

En este caso, todos son punteros a enteros constantes y ptr2 es puntero constante a enteros constantes . Pero ptr1 no es un puntero constante:

int const *ptr1=&i, *const ptr2=&j;
Cazador
fuente
3
  • si constestá a la izquierda de *, se refiere al valor (no importa si es const into int const)
  • si constestá a la derecha de *, se refiere al puntero mismo
  • puede ser ambos al mismo tiempo

Un punto importante: ¡ const int *p no significa que el valor al que se refiere es constante! . Significa que no puede cambiarlo a través de ese puntero (es decir, no puede asignar $ * p = ... `). El valor en sí mismo puede cambiarse de otras maneras. P.ej

int x = 5;
const int *p = &x;
x = 6; //legal
printf("%d", *p) // prints 6
*p = 7; //error 

Está destinado a ser utilizado principalmente en firmas de funciones, para garantizar que la función no pueda cambiar accidentalmente los argumentos pasados.

nota azul
fuente
2

Solo por completo para C siguiendo las otras explicaciones, no estoy seguro de C ++.

  • pp - puntero a puntero
  • p - puntero
  • datos - lo señalado, en ejemplos x
  • negrita - variable de solo lectura

Puntero

  • p datos - int *p;
  • p datos -int const *p;
  • p datos -int * const p;
  • p datos -int const * const p;

Puntero a puntero

  1. pp p data - int **pp;
  2. pp p data -int ** const pp;
  3. pp p data -int * const *pp;
  4. pp p data -int const **pp;
  5. pp p data -int * const * const pp;
  6. pp p data -int const ** const pp;
  7. pp p data -int const * const *pp;
  8. pp p data -int const * const * const pp;
// Example 1
int x;
x = 10;
int *p = NULL;
p = &x;
int **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 2
int x;
x = 10;
int *p = NULL;
p = &x;
int ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 3
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 4
int const x = 10; // Definition must happen during declaration
int const * p = NULL;
p = &x;
int const **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 5
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 6
int const x = 10; // Definition must happen during declaration
int const *p = NULL;
p = &x;
int const ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 7
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 8
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

N niveles de desreferencia

Solo sigue adelante, pero que la humanidad te excomulgue.

int x = 10;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
int ****pppp = &ppp;

printf("%d \n", ****pppp);
Comportamiento indefinido
fuente
0
  1. const int*- puntero al intobjeto constante .

Puede cambiar el valor del puntero; no puede cambiar el valor del intobjeto, apunta el puntero.


  1. const int * const- puntero constante al intobjeto constante .

No puede cambiar el valor del puntero ni el valor del intobjeto al que apunta el puntero.


  1. int const *- puntero al intobjeto constante .

Esta declaración es equivalente a 1. const int*- Puede cambiar el valor del puntero pero no puede cambiar el valor del intobjeto al que apunta el puntero.


En realidad, hay una cuarta opción:

  1. int * const- puntero constante al intobjeto.

Puede cambiar el valor del objeto al que apunta el puntero, pero no puede cambiar el valor del puntero en sí. El puntero siempre apuntará al mismo intobjeto, pero este valor de este intobjeto se puede cambiar.


Si desea determinar un determinado tipo de construcción C o C ++, puede usar la regla en sentido horario / espiral hecha por David Anderson; pero no confundir con la Regla de Anderson hecha por Ross J. Anderson, que es algo bastante distinto.

RobertS apoya a Monica Cellio
fuente