prohibiciones en literales de cuerdas en C

En la página 104 del libro de K&R, encontré esta statement:

char amessage[] = "now is the time"; //an array char *pmessage = "now is the time"; //a pointer 

Se pueden cambiar los caracteres individuales dentro de la matriz, pero el amessage siempre se referirá al mismo almacenamiento. El puntero de pmessage tarde puede modificarse posteriormente para que apunte a otra parte, pero el resultado no está definido si intenta modificar el contenido de la cadena …

Entonces, ¿sería este el error que significaron en ambos casos?

Para la matriz,

 amessage[] = "allocate to another address"; //wrong? 

Para el puntero,

 pmessage[0] = 'n'; //wrong? 

Solo quiero saber cuando uno va en contra de estas reglas.

Gracias.

 /* OK, modifying an array initialized by the * elements of a string literal */ amessage[0] = 'n'; /* not OK, modifying a string literal. * String literals are non-modifiable */ pmessage[0] = 'n'; 

Tenga en cuenta que en C no puede asignar matrices, por lo tanto, si desea copiar una matriz, use la función memcpy o use la función strcpy para copiar una cadena.

No hay nada intrínsecamente incorrecto en el uso de punteros como matrices, a menos que esos punteros apunten a datos constantes (y los literales de cadena son datos constantes). Aunque es semánticamente incorrecto, en los viejos tiempos sin protección de memoria, pmessage[0] = 'n'; realmente habría funcionado con resultados impredecibles (por ejemplo, afectando a todas las apariciones del mismo literal dentro del progtwig). En el sistema operativo moderno, esto no podría suceder debido a la protección de memoria instalada. Los literales de cadena y otras constantes se colocan en las llamadas secciones de solo lectura del ejecutable y cuando el ejecutable se carga en la memoria para crear un proceso, las páginas de memoria que contienen las secciones de solo lectura se convierten en de solo lectura. , es decir, cualquier bash de cambiar su contenido conduce a una falla de segementación.

 char amessage[] = "now is the time"; 

Es realmente un azúcar sintáctico para lo siguiente:

 char amessage[] = { 'n','o','w',' ','i','s',' ','t', 'h','e',' ','t','i','m','e','\0' }; 

es decir, crea una matriz de 16 caracteres e inicializa su contenido con la cadena “ahora es el momento” (junto con el terminador NULL).

Por otra parte

 char *pmessage = "now is the time"; 

coloca los mismos datos de cadena en algún lugar de los datos de solo lectura y asigna su dirección al puntero pmessage . Funciona similar a esto:

 // This one is in the global scope so the array is not on the stack const char _some_unique_name[] = "now is the time"; char *pmessage = _some_unique_name; 

_some_unique_name se elige para no chocar con ningún otro identificador en su progtwig. Normalmente se usan símbolos que no están permitidos por el lenguaje C, pero que están bien para el ensamblador y el enlazador (por ejemplo, puntos como en string.1634 ).

Puede cambiar el valor de un puntero; esto hará que apunte algo más, por ejemplo, a otra cadena. Pero no puede cambiar la dirección detrás del nombre de una matriz, es decir, el amessage siempre se referirá al mismo almacenamiento de matriz que se le asignó en primer lugar.

Puede referirse a elementos individuales de cada cadena usando amessage[i] o pmessage[i] pero solo puede asignar a los elementos de amessage ya que están ubicados en la memoria de lectura-escritura.

 char amessage[] = "now is the time"; /* ^ ^ (an array) (a string literal) */ 

Cuando utiliza un literal de cadena para inicializar una matriz de esta manera, está configurando los valores iniciales de los elementos de la matriz a los del propio literal. Y, por supuesto, a la matriz se le asigna su propia memoria separada. Y puedes modificar sus contenidos.

 char *pmessage = "now is the time"; /* ^ ^ (a pointer) (a string literal) */ 

Cuando utiliza un literal de cadena para inicializar un puntero, está haciendo que el puntero apunte a un literal de cadena. Este literal de cadena se puede almacenar en la memoria de solo lectura. Y por lo tanto no puede ser modificado. El puntero en sí puede ser modificado.

¿Qué es válido y qué no?

 amessage[0] = 'n'; /* Valid. Modifying array contents. */ amessage = pmessage; /* Invalid. You cannot assign to an array. */ pmessage[0] = 'n'; /* Invalid. You're trying to modify a string literal. */ 

Pero:

 pmessage = amessage; /* Valid. You're modifying a pointer. */ 

Después:

 pmessage[0] = 'n'; /* Valid. You just modified pmessage above, and it now points to modifiable memory. */ 

Finalmente: Hay una entrada de C-FAQ exactamente sobre esto . Vale la pena leerlo.

Inspirado por la respuesta de ouah . No quería hacer una gran edición para ello.

Si haces esto:

 char amessage[] = "now is the time"; //an array char *pmessage = "now is the time"; //a pointer 

Probablemente realmente quieras estar haciendo esto:

 const char *pmessage = "now is the time"; //a pointer 

Cuando se comstack su progtwig, en algún lugar de la memoria estarán los bytes “ahora es el tiempo” (tenga en cuenta que hay un terminador NULO). Esto estará en la memoria constante. No debe intentar cambiarlo; si lo hace, pueden ocurrir cosas extrañas (lo que sucederá dependerá de su entorno y si se almacena en la memoria de solo lectura o de lectura y escritura). Entonces, mientras K&R intentaba iluminarte sobre cómo podrías hacer las cosas, la forma pragmática es hacer que los punteros a constantes de cadenas consten, entonces el comstackdor se quejará si intentas cambiar los contenidos.

 char amessage[] = "now is the time"; //an array 

Un nombre de matriz es una constante. Es decir, la dirección de la matriz no se puede cambiar. Pero el contenido de la matriz se puede cambiar.

ASI QUE

 amessage[0]='n';//valid and it change the first element 

PERO

 amessage="hello";//if you try then it wrong as array address can not be changed 

Ahora ve la parte del puntero:

 char *pmessage = "now is the time"; //a pointer 

Como es un puntero, puede apuntar a cualquier dirección. Pero la ubicación de la dirección en la memoria puede ser modificable o no ser modificable. Esto puede ser de solo lectura o ambos pueden ser de lectura / escritura permitidos.

por lo tanto, cuando intente cambiar algunos datos en la memoria usando un mensaje de puntero, dependerá de la memoria de puntero que dependa del resultado. Aquí apunta a la sección de código, así que solo lectura. Por lo tanto, no se permite la modificación.

asi que

 pmessage[0]='n';//definitely give you error