usar - Diferencia entre char*y const char*?
strings en c (9)
Cuál es la diferencia entre
char* name
que apunta a un literal de cadena constante, y
const char* name
CASO 1:
char *str = "Hello";
str[0] = ''M'' //No warning or error, just Undefined Behavior
Lo anterior establece str para apuntar al valor literal "Hello", que está codificado en la imagen binaria del programa, que está marcada como de solo lectura en la memoria, significa que cualquier cambio en este literal de Cadena es ilegal y arrojaría fallas de segmentación.
CASO 2:
const char *str = "Hello";
str[0] = ''M'' //Compiler issues a warning
CASO 3:
char str[] = "Hello";
str[0] = ''M''; // legal and change the str = "Mello".
El primero que realmente puede cambiar si lo desea, el segundo no puede. Lea acerca de la exactitud const
(hay algunas buenas guías sobre la diferencia). También hay un char const * name
donde no puede volver a marcarlo.
En ninguno de los casos puede modificar un literal de cadena, independientemente de si el puntero a ese literal de cadena se declara como char *
o const char *
.
Sin embargo, la diferencia es que si el puntero es const char *
, el compilador debe dar un diagnóstico si intenta modificar el valor apuntado, pero si el puntero es char *
no lo hace.
En realidad, el char* name
no es un puntero a una constante, sino un puntero a una variable. Usted podría estar hablando de esta otra pregunta.
La pregunta es ¿cuál es la diferencia entre
char *name
que apunta a un literal de cadena constante, y
const char *cname
Es decir,
char *name = "foo";
y
const char *cname = "foo";
No hay mucha diferencia entre los 2 y ambos se pueden ver como correctos. Debido al largo legado del código C, los literales de cadena han tenido un tipo de char[]
, no const char[]
, y hay muchos códigos anteriores que también aceptan char *
lugar de const char *
, incluso cuando no lo hacen modificar los argumentos.
La principal diferencia de los 2 en general es que *cname
o cname[n]
evaluará a lvalues de tipo const char
, mientras que *name
o name[n]
evaluará a lvalues de tipo char
, que son valores modificables . Se requiere un compilador conforme para generar un mensaje de diagnóstico si el objetivo de la asignación no es un valor l modificable ; no necesita producir ninguna advertencia en la asignación a lvalues de tipo char
:
name[0] = ''x''; // no diagnostics *needed*
cname[0] = ''x''; // a conforming compiler *must* produce a diagnostics message
El compilador no está obligado a detener la compilación en ningún caso; es suficiente que produzca una advertencia para la asignación a cname[0]
. El programa resultante no es un programa correcto . El comportamiento de la construcción no está definido . Puede fallar, o incluso peor, puede no bloquearse, y puede cambiar el literal de la cadena en la memoria.
Solo para dar un ejemplo extra:
std::cout << typeid(2.3).name() << ''/n''; // -----> prints "double" simply because
//2.3 is a double
//But the "double" returned by typeid(2.3).name() is indeed a
//const char * which consists of ''d'',''o'',''u'',''b'',''l'',''e''and''/0''.
//Here''s a simple proof to this:
std::cout << typeid(typeid(2.3).name()).name() << ''/n''; //prints: "const char *"
const char* charptr
charptr = typeid(2.3).name();
std::cout << charptr[3]; // ---------> prints: "b"
(Estoy usando la biblioteca typeinfo: http://www.cplusplus.com/reference/typeinfo/type_info/name )
//Now let''s do something more interesting:
char* charptr2="hubble";
strcpy(charptr, charptr2); // --------> Oops! Sorry, this is not valid!
Puede ejecutarlo y ver las cosas mejor para usted.
char*
es un puntero mutable a un carácter / cadena mutable .
const char*
es un puntero mutable a un carácter / cadena inmutable . No puede cambiar el contenido de las ubicaciones a las que apunta este puntero. Además, se requiere que los compiladores den mensajes de error cuando intentas hacerlo. Por la misma razón, la conversión de const char *
a char*
está en desuso.
char* const
es un puntero inmutable (no puede señalar a ninguna otra ubicación) pero el contenido de la ubicación en el que apunta es mutable .
const char* const
es un puntero inmutable para un carácter / cadena inmutable .
char *name
Puede cambiar el carácter al que apunta, y también el carácter al que apunta.
const char* name
Puedes cambiar el carácter al que apunta el name
, pero no puedes modificar el carácter al que apunta.
corrección: puede cambiar el puntero, pero no el carácter al que apunta ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , consulte "Ejemplos "). En este caso, el especificador const
se aplica a char
, no al asterisco.
De acuerdo con la página de MSDN y http://en.cppreference.com/w/cpp/language/declarations , la const
antes de *
es parte de la secuencia del especificador de declinación, mientras que la const
después de *
es parte del declarador.
Una secuencia de especificador de declaración puede ser seguida por múltiples declaradores, por lo que const char * c1, c2
declara c1
como const char *
y c2
como const char
.
EDITAR:
A partir de los comentarios, su pregunta parece estar preguntando sobre la diferencia entre las dos declaraciones cuando el puntero apunta a un literal de cadena.
En ese caso, no debe modificar el carácter al que apunta el name
, ya que podría provocar un comportamiento no definido . Los literales de cadena pueden asignarse en regiones de memoria de solo lectura (implementación definida) y un programa de usuario no debería modificarlo de ninguna manera. Cualquier intento de hacerlo da como resultado un Comportamiento Indefinido.
Entonces la única diferencia en ese caso (de uso con literales de cadena) es que la segunda declaración le da una ligera ventaja. Los compiladores generalmente le darán una advertencia en caso de que intente modificar el literal de la cadena en el segundo caso.
#include <string.h>
int main()
{
char *str1 = "string Literal";
const char *str2 = "string Literal";
char source[] = "Sample string";
strcpy(str1,source); //No warning or error, just Undefined Behavior
strcpy(str2,source); //Compiler issues a warning
return 0;
}
Salida:
cc1: advertencias que se tratan como errores
prog.c: en la función ''principal'':
prog.c: 9: error: pasar el argumento 1 de ''strcpy'' descarta los calificadores del tipo de objetivo de puntero
Observe que el compilador advierte para el segundo caso pero no para el primero.
char mystring[101] = "My sample string";
const char * constcharp = mystring; // (1)
char const * charconstp = mystring; // (2) the same as (1)
char * const charpconst = mystring; // (3)
constcharp++; // ok
charconstp++; // ok
charpconst++; // compile error
constcharp[3] = ''/0''; // compile error
charconstp[3] = ''/0''; // compile error
charpconst[3] = ''/0''; // ok
// String literals
char * lcharp = "My string literal";
const char * lconstcharp = "My string literal";
lcharp[0] = ''X''; // Segmentation fault (crash) during run-time
lconstcharp[0] = ''X''; // compile error
// *not* a string literal
const char astr[101] = "My mutable string";
astr[0] = ''X''; // compile error
((char*)astr)[0] = ''X''; // ok