¿Cuál es la diferencia entre const int*, const int * const e int const *?
⏰ 11 minutos de lectura
Siempre me lío cómo usar const int*, const int * consty int const * correctamente. ¿Existe un conjunto de reglas que definan lo que puede y no puede hacer?
Quiero saber todo lo que se debe y no se debe hacer en términos de asignaciones, pasar a las funciones, etc.
cdecl.org es un gran sitio web que traduce automáticamente declaraciones C para usted.
– Dave
2 de noviembre de 2010 a las 19:37
@Calmarius: comience donde está/debe estar el nombre del tipo, muévase a la derecha cuando pueda, a la izquierda cuando deba. int *(*)(char const * const). Comience a la derecha del paréntesis * entonces tenemos que movernos a la izquierda: pointer. Fuera de los paréntesis, podemos movernos a la derecha: pointer to function of .... Luego tenemos que movernos a 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 fácil de leer como Pascal?
– Mark K. Cowan
9 de julio de 2015 a las 17:08
@MarkKCowan En Pascal sería algo así como function(x:^char):^int. Hay tipos de funciones que implican un puntero a una función, por lo que no es necesario especificarlo, y Pascal no impone la corrección constante. Se puede leer de izquierda a derecha.
– Calmarius
9 de julio de 2015 a las 20:54
Lo primero a la izquierda de “const” 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.
ahora el primero const puede estar a ambos lados del tipo, por lo que:
const int * == int const *
const int * const == int const * const
Si quieres volverte realmente loco, puedes hacer cosas como esta:
int ** – puntero a puntero a int
int ** const – un puntero const a un puntero a un int
int * const * – un puntero a una const puntero a un int
int const ** – un puntero a un puntero a una const int
int * const * const – un puntero const a un puntero const 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.
foo es un puntero variable a un entero constante. Esto le permite cambiar lo que apunta, pero no el valor 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 la cadena a la que apunta, pero no puede cambiar el contenido de estas cadenas. Esto es importante cuando la propia cadena está en el segmento de datos de un programa y no debe cambiarse.
bar es 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, generalmente usaría una referencia donde usaría un T* const puntero a menos que necesite permitir NULL punteros
Me gustaría agregar una regla general que puede ayudarlo a recordar cómo descubrir si ‘const’ se aplica al puntero o a los datos señalados: 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 apuntados, si está en la parte derecha (‘int * const bar’) – se trata del puntero.
– Miguel
17 de julio de 2009 a las 17:26
@Michael: Felicitaciones a Michael por una regla tan simple para recordar/comprender la regla constante.
– sivabudh
11 de febrero de 2010 a las 19:00
@Jeffrey: leerlo al revés funciona bien siempre que no haya paréntesis. Pues… usar definiciones de tipo
– Pato mugido
28 mayo 2013 a las 19:53
+1, aunque un mejor resumen sería: leer declaraciones de puntero al revéseso significa, cerca de la declaración de @Michael: detener la lectura normal de izquierda a derecha en el primero asterisco.
– Lobo
18 de junio de 2014 a las 9:21
@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
08/08/2016 a las 23:15
Shijing Nv
Para aquellos que no saben acerca de la regla de las agujas del reloj/espiral: Comience desde el nombre de la variable, muévase en el sentido de las agujas del reloj (en este caso, muévase hacia atrás) a la siguiente puntero o escribe. Repita hasta que termine la expresión.
Aquí hay una demostración:
@Jan el enlace para el ejemplo complejo no tiene permisos. ¿Puedes publicarlo directamente aquí o eliminar las restricciones de visualización?
– R71
8 de abril de 2016 a las 12:03
@Rog solía tener todos los permisos de acceso abierto… Desafortunadamente, no escribí el artículo y no tengo permisos de acceso. Sin embargo, aquí hay una versión archivada del artículo que aún funciona: archivo.is/SsfMX
– Jan Rüegg
08/04/2016 a las 13:34
El ejemplo complejo sigue siendo de derecha a izquierda, pero incluye la resolución de paréntesis como se haría normalmente. Todo el asunto de la espiral en el sentido de las agujas del reloj no lo hace más fácil.
– Mateo Lee
18/09/2016 a las 23:04
Último ejemplo: void (*signal(int, void (*fp)(int)))(int); de archive.is/SsfMX
– naXa
3 mayo 2017 a las 19:04
No confíe en esta regla. Esto no es universal. Hay algunos casos en los que falla.
– trucos
12 de mayo de 2017 a las 7:17
Dragón Kaz
Creo que todo ya está respondido aquí, pero solo quiero agregar que debes tener cuidado con typedef¡s! NO son solo reemplazos de texto.
Por ejemplo:
typedef char *ASTRING;
const ASTRING astring;
El tipo de astring es char * constno const char *. Esta es una razón por la que siempre tiendo a poner const a la derecha del tipo, y nunca al principio.
Y para mí, esta es la razón por la que nunca tipeo los punteros def. No veo el beneficio en cosas como typedef int* PINT (Supongo que es algo que surgió de las prácticas en C y muchos desarrolladores siguieron haciéndolo). Genial, lo reemplacé * con un Pno acelera la escritura, además de presentar el problema que mencionas.
– Mefane
28 de enero de 2011 a las 13:01
@Mephane – Puedo ver eso. Sin embargo, me parece un poco al revés evitar una función de lenguaje agradable para seguir usando una regla sintáctica excepcional (sobre la ubicación de “const”), en lugar de evitar el uso de la regla sintáctica excepcional para que pueda usar esta función de lenguaje de manera segura. .
– TED
17 de octubre de 2012 a las 14:06
@Mephane PINT es de hecho un uso bastante tonto de un typedef, especialmente porque me hace pensar que las tiendas del sistema usan cerveza para la memoria. Sin embargo, typedef s son bastante útiles para tratar con punteros a funciones.
– Acercándose a la OscuridadPez
26 de diciembre de 2013 a las 21:07
@KazDragon ¡GRACIAS! Sin él, me habría equivocado con todos esos typedefed PVOID, LPTSTR cosas en Win32 api!
–David Lee
8 mayo 2014 a las 12:29
@Mephane: Tuve que usar pAlgo un par de veces cuando usaba ciertas macros heredadas que se escribieron para aceptar un tipo, pero se separarían si el tipo no fuera un único identificador alfanumérico. 🙂
Tienes que 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 en sí, 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í mismo, ni puede cambiar el objeto X a través de p.
Behrooz Tabesh
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 que el valor real, pero hay un efecto secundario y es que es como un alias de la variable real. Es posible que cambiemos 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
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
Puntero a constante
Un puntero a través del cual no se puede cambiar el valor de una variable a la que apunta se conoce como puntero a constante.
int const * ptr3 = &var2;
*ptr3 = 4; // Error
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 ni 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
Azeem
La regla general es que el const palabra clave se aplica a lo que le precede inmediatamente. Excepción, un comienzo const se aplica a lo que sigue.
const int* es lo mismo que int const* y medios “puntero a int constante”.
const int* const es lo mismo que int const* const y medios “puntero constante a int constante”.
Editar:
Para lo que se debe y lo que no se debe hacer, si esta respuesta no es suficiente, ¿podría ser más preciso sobre lo que quiere?
Comunidad
Esta pregunta muestra precisamente ¿Por qué me gusta hacer las cosas de la manera que mencioné en mi pregunta es constante después de la identificación del tipo aceptable?
En resumen, creo que la forma más fácil de recordar la regla es que la “const” va después la cosa a la que se aplica. Entonces, en su pregunta, “int const *” significa que int es constante, mientras que “int * const” significaría que el puntero es constante.
Si alguien decide ponerlo al principio (p. ej.: “const int *”), como excepción especial en ese caso, se aplica a lo que sigue.
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.
Estoy desgarrado en 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 alguna vez usa un T* const de todos modos, por lo general una referencia funcionará bien. Me mordió todo esto una vez cuando quería un boost::shared_ptr<const T> y en su lugar escribió const boost::shared_ptr<T>. El mismo problema en un contexto ligeramente diferente.
– Precio mate
17 de julio de 2009 a las 14:08
En realidad, uso punteros constantes con más frecuencia que constantes. Además, debe pensar en cómo va a reaccionar en presencia de punteros a punteros (etc.). Es cierto que esos son más raros, pero sería bueno pensar en las cosas de una manera en la que pueda manejar estas situaciones con aplomo.
– TED
17 de julio de 2009 a las 14:19
La otra buena ventaja de colocar la const a la derecha del tipo es que ahora todo a la izquierda de cualquier const es el tipo de lo que es const, y todo a su derecha es lo que en realidad es const. Llevar 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: el tipo es un puntero a const int, const oblect es el contenido de p
– dnuff
15 de marzo de 2018 a las 7:18
¿Ha sido útil esta solución?
Tu feedback nos ayuda a saber si la solución es correcta y está funcionando. De esta manera podemos revisar y corregir el contenido.
Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos.
Configurar y más información
Puedes usar el “Regla en el sentido de las agujas del reloj/espiral” para descifrar la mayoría de las declaraciones de C y C++.
–James McNellis
13 de junio de 2010 a las 20:49
cdecl.org es un gran sitio web que traduce automáticamente declaraciones C para usted.
– Dave
2 de noviembre de 2010 a las 19:37
@Calmarius: comience donde está/debe estar el nombre del tipo, muévase a la derecha cuando pueda, a la izquierda cuando deba.
int *(*)(char const * const)
. Comience a la derecha del paréntesis*
entonces tenemos que movernos a la izquierda:pointer
. Fuera de los paréntesis, podemos movernos a la derecha:pointer to function of ...
. Luego tenemos que movernos a 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 fácil de leer como Pascal?– Mark K. Cowan
9 de julio de 2015 a las 17:08
@MarkKCowan En Pascal sería algo así como
function(x:^char):^int
. Hay tipos de funciones que implican un puntero a una función, por lo que no es necesario especificarlo, y Pascal no impone la corrección constante. Se puede leer de izquierda a derecha.– Calmarius
9 de julio de 2015 a las 20:54
Lo primero a la izquierda de “const” 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
31 de julio de 2016 a las 4:41