const char * y char const *: ¿son iguales?

81

Según tengo entendido, los constmodificadores deben leerse de derecha a izquierda. De eso, lo entiendo:

const char*

es un puntero cuyos elementos char no se pueden modificar, pero el puntero en sí sí puede, y

char const*

es un puntero constante a los mutablecaracteres.

Pero obtengo los siguientes errores para el siguiente código:

const char* x = new char[20];
x = new char[30];   //this works, as expected
x[0] = 'a';         //gives an error as expected

char const* y = new char[20];
y = new char[20];   //this works, although the pointer should be const (right?)
y[0] = 'a';         //this doesn't although I expect it to work

Entonces ... ¿cuál es? ¿Mi comprensión o mi compilador (VS 2005) son incorrectos?

Luchian Grigore
fuente
35
En caso de duda, utilice siempre la regla de la espiral .
Alok Save
"... cuyos elementos char se pueden modificar, pero el puntero sí puede, y ..." - Creo que querías decir "no puedo" para una de esas "latas", pero no sé cómo confundido estás, así que no sé cuál corregir: P
detly
1
Pruebe este sitio web: www.cdecl.org
yasouser
El compilador nunca se equivoca;)
monolith

Respuestas:

129

En realidad, según el estándar, constmodifica el elemento directamente a su izquierda . El uso de constal comienzo de una declaración es solo un atajo mental conveniente. Entonces, las siguientes dos declaraciones son equivalentes:

char const * pointerToConstantContent1;
const char * pointerToConstantContent2;

Para asegurarse de que el puntero en sí no se modifique, constdebe colocarse después del asterisco:

char * const constantPointerToMutableContent;

Para proteger tanto el puntero como el contenido al que apunta, utilice dos consts.

char const * const constantPointerToConstantContent;

Personalmente, he adoptado siempre poner la constante después de la parte que no pretendo modificar para mantener la coherencia incluso cuando el puntero es la parte que deseo mantener constante.

Greyson
fuente
23
'taquigrafía conveniente' es una descripción interesante para algo que no es más corto y no sigue las reglas normales.
beetstra
Al estándar realmente no le importa qué orden uses. La sección 7.1.6 solo muestra ambos lugares y dice que lo use solo en uno.
edA-qa mort-ora-y
1
@beetstra estoy de acuerdo. Lo cambié a "atajo mental conveniente" para ser un poco más claro.
Greyson
31

Funciona porque ambos son iguales. Puede que estés confundido en esto

const char*  // both are same
char const*

y

char* const  // unmutable pointer to "char"

y

const char* const  // unmutable pointer to "const char"

[Para recordar esto, aquí hay una regla simple, '*' afecta primero a todo su LHS ]

iammilind
fuente
Ok, lo tengo ahora. Muchas gracias.
Luchian Grigore
1
unmutable pointer to char*.Es un puntero inmutable que apunta a charno char *.
Alok Save
25

Eso es porque la regla es:

REGLA: se constune a la izquierda, a menos que no haya nada a la izquierda, entonces se une a la derecha :)

entonces, mira estos como:

(const --->> char)*
(char <<--- const)*

ambos iguales! ah, y --->>y <<---NO son operadores, que acaba de mostrar lo que los constune a.

Akanksh
fuente
2
sí, el operador correcto es -->>y opera solo con valores. Prueba int i = 8; std::cout << (i -->> 1) << std::endl;:)
Alexander Malakhov
11

(de 2 pregunta de inicialización de variable simple )

Una muy buena regla general con respecto a const:

Leer declaraciones de derecha a izquierda.

(ver Vandevoorde / Josutiss "Plantillas C ++: La guía completa")

P.ej:

int const x; // x is a constant int
const int x; // x is an int which is const

// easy. the rule becomes really useful in the following:
int const * const p; // p is const-pointer to const-int
int const &p;        // p is a reference to const-int
int * const * p;     // p is a pointer to const-pointer to int.

Desde que sigo esta regla empírica, nunca volví a interpretar mal tales declaraciones.

(: sisab retcarahc-rep a no ton, sisab nekot-rep a no tfel-ot-thgir naem I hguohT: tidE

Sebastián Mach
fuente
+1 ¡Esto es fantástico, gracias! He estado tratando de entender cosas como const char* constdurante años y gracias a ti ahora lo entiendo.
OMGtechy
5

Así es como siempre trato de interpretar:

char *p

     |_____ start from the asterisk. The above declaration is read as: "content of `p` is a `char`".

char * const p

     |_____ again start from the asterisk. "content of constant (since we have the `const` 
            modifier in the front) `p` is a `char`".

char const *p

           |_____ again start from the asterisk. "content of `p` is a constant `char`".

¡Espero eso ayude!

yasuser
fuente
0

En ambos casos, estás apuntando a un carácter constante.

const char * x  //(1) a variable pointer to a constant char
char const * x  //(2) a variable pointer to a constant char
char * const x  //(3) a constant pointer to a variable char
char const * const x //(4) a constant pointer to a constant char
char const * const * x //(5) a variable pointer to a constant pointer to a constant char
char const * const * const x //(6) can you guess this one?

Por defecto, se constaplica a lo que está inmediatamente a la izquierda, pero podría aplicarse a lo que está inmediatamente a su derecha si no hay nada que lo preceda, como en (1).

Lino Mediavilla
fuente
Último: un puntero de variable constante, a un puntero constante, a un carácter constante.
Secko
Si por "puntero de variable constante" te refieres a "puntero constante", ¡lo has clavado hermano!
Lino Mediavilla
Bueno, en (5) ese es un puntero variable a un puntero constante a un carácter constante simplemente porque no hay "const" a la derecha del último asterisco antes del identificador "x". Pero en (6) eso se convierte en un puntero constante, el resto permanece igual.
Lino Mediavilla