¿Qué quieres decir con " literal de cadena constante " en C (no C ++)
gbulmer
1
... char * name se puede hacer que apunte a un literal de cadena constante
Iceman
la constante en "literal de cadena constante" es redundante, ya que todos los literales de cadena son en teoría entidades constantes. Es el contenido de la variable que puede hacerse constante o mutable. La declaración "const" simplemente arrojará un error de tiempo de compilación si intenta cambiar el contenido del personaje señalado por "nombre"
Cupcake
Simple: el nombre "char * name" es un puntero a char, es decir, ambos se pueden cambiar aquí. El nombre "const char * name" es un puntero a const char, es decir, el puntero puede cambiar pero no char.
akD
Lea estas cosas de derecha a izquierda.
Jiapeng Zhang
Respuestas:
406
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, los compiladores deben enviar mensajes de error cuando intentas hacerlo. Por la misma razón, la conversión de const char *a char*está en desuso.
char* constes un puntero inmutable (no puede apuntar a ninguna otra ubicación) pero los contenidos de la ubicación a la que apunta son mutables .
const char* constes un puntero inmutable a un carácter / cadena inmutable .
La confusión puede aclararse con el uso de una variable después de las declaraciones mencionadas anteriormente y al hacer referencia a esa variable.
ankit.karwasra
3
@ ankit.karwasra, te perdiste uno más:char const *
Pacerier
Supongo que dos opciones con caracteres / cadenas mutables son muy peligrosas, ya que podrías hacer una memoria de falla de segmentación y, si eres realmente inteligente, podrías hackear la computadora. Es por eso que los compiladores siempre mostraron advertencias en esas implementaciones, creo
Daniel N.
1
¿La mutación no char *da error de segmentación mientras se ejecuta?
Divyanshu Maithani
1
Entonces uso constsi quiero que el compilador dé un error si olvidé y cambié los datos por error, ¿verdad?
Contador م
43
char*name
Puede cambiar el carácter a qué namepuntos, y también el carácter al que apunta.
constchar* name
Puede cambiar el carácter a qué namepuntos, pero no puede modificar el carácter al que apunta. corrección: puede cambiar el puntero, pero no el carácter al que nameapunta ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , consulte "Ejemplos" ) En este caso, el constespecificador se aplica char, no el asterisco.
De acuerdo con la página de MSDN y http://en.cppreference.com/w/cpp/language/declarations , el constantes *es parte de la secuencia de rechazo-especificador, mientras que el constdespués *es parte del declarador.
Una secuencia de especificador de declaración puede ser seguida por múltiples declaradores, razón por la cual const char * c1, c2declara c1as const char *y c2as const char.
EDITAR:
A partir de los comentarios, su pregunta parece ser la diferencia entre las dos declaraciones cuando el puntero apunta a un literal de cadena.
En ese caso, no debe modificar el carácter a qué namepuntos, ya que podría dar lugar a un comportamiento indefinido . Los literales de cadena se pueden asignar en regiones de memoria de solo lectura (implementación definida) y un programa de usuario no debe 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 cadena en el segundo caso.
#include<string.h>int main(){char*str1 ="string Literal";constchar*str2 ="string Literal";char source[]="Sample string";
strcpy(str1,source);//No warning or error, just Undefined Behavior
strcpy(str2,source);//Compiler issues a warningreturn0;}
Salida:
cc1: las advertencias se tratan como errores
prog.c: en la función 'main':
prog.c: 9: error: pasar el argumento 1 de 'strcpy' descarta los calificadores del tipo de destino del puntero
Observe que el compilador advierte para el segundo caso pero no para el primero.
Gracias ... me estaba mezclando con el literal de cadena constante, que se define como: char * name = "String Literal"; Cambiar "String Literal" no está definido ..
Iceman
@ user1279782: ¡Err, espera! ¿Estás hablando de pointes apuntando a literales de cadena aquí? En ese caso , no debe modificar el carácter al que nameapuntan en ninguno de los casos, ya que podría dar lugar a UB.
Alok Save
Sí, ese era el punto. Entonces, en ese caso, char * name y const char * name se comportan de manera similar, ¿verdad?
Iceman
44
Esta respuesta es extremadamente ambigua o simplemente errónea. Interpretaría "No puede cambiar el carácter al que apunta el nombre, pero puede modificar el carácter al que apunta". Como no ser capaz de modificar el puntero en sí, pero ser capaz de modificar la posición de memoria al que apunta, lo cual es incorrecto: ideone.com/6lUY9s alternativamente por pura C: ideone.com/x3PcTP
shroudednight
1
@shroudednight: necesita aprender un poco más sobre comportamientos indefinidos y debe distinguir entre: permitido y no debe hacerse. :)
Alok Save
16
char mystring[101]="My sample string";constchar* constcharp = mystring;// (1)charconst* 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 literalschar* lcharp ="My string literal";constchar* lconstcharp ="My string literal";
lcharp[0]='X';// Segmentation fault (crash) during run-time
lconstcharp[0]='X';// compile error// *not* a string literalconstchar astr[101]="My mutable string";
astr[0]='X';// compile error((char*)astr)[0]='X';// ok
Ninguno de sus punteros apunta a "literales de cadena constantes" según la pregunta.
caf
Vale la pena señalar que cambiar el char *valor da un error de segmentación ya que estamos tratando de modificar un literal de cadena (que está presente en la memoria de solo lectura)
Divyanshu Maithani
10
En ningún caso 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 señalado, pero si el puntero es, char *entonces no lo hace.
"En ningún caso puede modificar un literal de cadena, independientemente de si ... [se] declara como char * o const char *" Estoy de acuerdo en que el programador no debe intentarlo, pero ¿está diciendo que cada compilador de C, en cada la plataforma rechazará el código, organizará el error del código en el tiempo de ejecución, o algo más? Creo que un archivo podría tener la definición y la inicialización, y otro archivo podría contener extern ... namey tener *name = 'X';. En el 'sistema operativo adecuado', eso podría fallar, pero en los sistemas integrados, esperaría que hiciera algo específico para la plataforma / compilador.
Gbulmer
@gbulmer: no puede modificar un literal de cadena en un programa C correcto. Lo que puede resultar en un programa C incorrecto que intenta no está ni aquí ni allá.
caf
@gbulmer: Una definición útil es un programa que no rompe las restricciones especificadas por el estándar del lenguaje C. En otras palabras, un programa que modifica un literal de cadena es incorrecto de la misma manera que uno que desreferencia un puntero nulo o realiza una división por 0 es incorrecto.
caf
caf - Pensé que eso podría ser lo que querías decir. Entonces "En ningún caso puede modificar un literal de cadena" parece haber terminado de indicarlo. Sería exacto decir "En ambos casos, las restricciones especificadas por el estándar del lenguaje C se han roto, independientemente ... No es posible que el compilador o el sistema de tiempo de ejecución identifique infracciones del estándar en todos los casos". ¿Asumo que el estándar toma la posición de que el efecto no está definido?
gbulmer
1
Cuando un estándar no puede afirmar nada de ninguna manera, creo que definir el comportamiento como 'indefinido' parece ser exactamente el límite correcto y útil. Para afirmar la relación, un 'programa C correcto' ' no puede desreferenciar un puntero nulo' suena equivalente a probar el problema de detención. Pero no me importa No lo haría y esperaría salir con la suya 'scott free' :-)
gbulmer
4
CASO 1:
char*str ="Hello";
str[0]='M'//Warning may be issued by compiler, and will cause segmentation fault upon running the programme
Lo anterior establece que str apunte al valor literal "Hola", que está codificado en la imagen binaria del programa, que está marcado 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:
constchar*str ="Hello";
str[0]='M'//Compile time error
CASO 3:
char str[]="Hello";
str[0]='M';// legal and change the str = "Mello".
Lo primero que puedes cambiar realmente si quieres, lo segundo no puedes. Lea sobre la constcorrección (hay algunas buenas guías sobre la diferencia). También hay un lugar char const * namedonde no puedes cambiarlo.
No hay mucha diferencia entre los 2 y ambos pueden verse 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 antiguos que también aceptan en char *lugar de const char *, incluso cuando no modifican los argumentos.
La principal diferencia de los 2 en general es que *cnameo cname[n]evaluará valores de tipo const char, mientras que *nameo name[n]evaluará valores 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 modificable ; no necesita producir ninguna advertencia sobre la asignación a valores 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 ninguno de los casos; es suficiente que produzca una advertencia para la asignación cname[0]. El programa resultante no es un programa correcto . El comportamiento de la construcción es indefinido . Puede bloquearse, o peor aún, podría no bloquearse y cambiar el literal de cadena en la memoria.
Respuestas:
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, los compiladores deben enviar mensajes de error cuando intentas hacerlo. Por la misma razón, la conversión deconst char *
achar*
está en desuso.char* const
es un puntero inmutable (no puede apuntar a ninguna otra ubicación) pero los contenidos de la ubicación a la que apunta son mutables .const char* const
es un puntero inmutable a un carácter / cadena inmutable .fuente
char const *
char *
da error de segmentación mientras se ejecuta?const
si quiero que el compilador dé un error si olvidé y cambié los datos por error, ¿verdad?Puede cambiar el carácter a qué
name
puntos, y también el carácter al que apunta.Puede cambiar el carácter a quéname
puntos, pero no puede modificar el carácter al que apunta.corrección: puede cambiar el puntero, pero no el carácter al que
name
apunta ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , consulte "Ejemplos" ) En este caso, elconst
especificador se aplicachar
, no el asterisco.De acuerdo con la página de MSDN y http://en.cppreference.com/w/cpp/language/declarations , el
const
antes*
es parte de la secuencia de rechazo-especificador, mientras que elconst
después*
es parte del declarador.Una secuencia de especificador de declaración puede ser seguida por múltiples declaradores, razón por la cual
const char * c1, c2
declarac1
asconst char *
yc2
asconst char
.EDITAR:
A partir de los comentarios, su pregunta parece ser la diferencia entre las dos declaraciones cuando el puntero apunta a un literal de cadena.
En ese caso, no debe modificar el carácter a qué
name
puntos, ya que podría dar lugar a un comportamiento indefinido . Los literales de cadena se pueden asignar en regiones de memoria de solo lectura (implementación definida) y un programa de usuario no debe 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 cadena en el segundo caso.
Ejemplo de muestra en línea:
Salida:
Observe que el compilador advierte para el segundo caso pero no para el primero.
fuente
name
apuntan en ninguno de los casos, ya que podría dar lugar a UB.fuente
char *
valor da un error de segmentación ya que estamos tratando de modificar un literal de cadena (que está presente en la memoria de solo lectura)En ningún caso puede modificar un literal de cadena, independientemente de si el puntero a ese literal de cadena se declara como
char *
oconst 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 señalado, pero si el puntero es,char *
entonces no lo hace.fuente
extern ... name
y tener*name = 'X';
. En el 'sistema operativo adecuado', eso podría fallar, pero en los sistemas integrados, esperaría que hiciera algo específico para la plataforma / compilador.CASO 1:
Lo anterior establece que str apunte al valor literal "Hola", que está codificado en la imagen binaria del programa, que está marcado 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:
CASO 3:
fuente
Lo primero que puedes cambiar realmente si quieres, lo segundo no puedes. Lea sobre la
const
corrección (hay algunas buenas guías sobre la diferencia). También hay un lugarchar const * name
donde no puedes cambiarlo.fuente
La pregunta es cuál es la diferencia entre
que apunta a un literal de cadena constante, y
Es decir
y
No hay mucha diferencia entre los 2 y ambos pueden verse como correctos. Debido al largo legado del código C, los literales de cadena han tenido un tipo de
char[]
, noconst char[]
, y hay muchos códigos antiguos que también aceptan enchar *
lugar deconst char *
, incluso cuando no modifican los argumentos.La principal diferencia de los 2 en general es que
*cname
ocname[n]
evaluará valores de tipoconst char
, mientras que*name
oname[n]
evaluará valores de tipochar
, 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 modificable ; no necesita producir ninguna advertencia sobre la asignación a valores de tipochar
:El compilador no está obligado a detener la compilación en ninguno de los casos; es suficiente que produzca una advertencia para la asignación
cname[0]
. El programa resultante no es un programa correcto . El comportamiento de la construcción es indefinido . Puede bloquearse, o peor aún, podría no bloquearse y cambiar el literal de cadena en la memoria.fuente
En realidad,
char* name
no es un puntero a una constante, sino un puntero a una variable. Tal vez estés hablando de esta otra pregunta.¿Cuál es la diferencia entre char * const y const char *?
fuente