Modificar una cadena char * const

Sé que const char * es un puntero a un const char, mientras que char *const es un puntero constante a un char. Estoy probando esto en el siguiente código:

 const char *s = "hello"; // Not permitted to modify the string "hello" char *const t = "world"; // Not permitted to modify the pointer t s = "hello2"; // Valid // t = "world2"; // Invalid, gives comstacktion error // *(s + 1) = 'a'; // Invalid, gives comstacktion error *(t + 1) = 'a'; // Why does this not work? 

La última línea no genera ningún error, pero hace que el progtwig finalice inesperadamente. ¿Por qué la modificación de la cadena apuntada por t no está permitida?

t apunta a un literal de cadena , es un comportamiento indefinido modificar un literal de cadena . El borrador de la sección estándar de C ++ 2.14.5 cadenas, párrafo 12, dice (el énfasis es mío ):

Si todos los literales de cadena son distintos (es decir, se almacenan en objetos no superpuestos) se define la implementación. El efecto de intentar modificar un literal de cadena no está definido .

La sección relevante del proyecto de norma C99 es 6.4.5 Cadenas literales párrafo 6 que dice (el énfasis es mío ):

No se especifica si estas matrices son distintas siempre que sus elementos tengan los valores adecuados. Si el progtwig intenta modificar dicha matriz, el comportamiento no está definido.

En una plataforma moderna típica de Unix, encontrará literales de cadenas en el segmento de solo lectura, lo que daría lugar a una infracción de acceso si intentamos modificarlo. Podemos usar objdump para inspeccionar la sección de solo lectura de la siguiente manera:

 objdump -s -j .rodata 

podemos ver en el siguiente ejemplo en vivo que el literal de cadena se encontrará efectivamente en la sección de solo lectura . Tenga en cuenta que tuve que agregar un printf contrario, el comstackdor optimizaría el literal de la cadena. Muestra `salida objdump :

 Contents of section .rodata: 400668 01000200 776f726c 64002573 0a00 ....world.%s.. 

Un enfoque alternativo sería t apuntar a una matriz con una copia de una cadena literal como ese:

 char r[] = "world"; char *const t = r ; 

Aunque los literales de cadena en C tienen oficialmente un tipo de char[] (matriz de char , no const ), el estándar C especifica que deben tratarse como no modificables. Los comstackdores tienden a poner literales de cadena en un segmento de solo lectura, por lo que intentar modificarlos genera una infracción de acceso.

Los literales de cadena se describen en la sección 6.4.5 del estándar C11 (ISO / IEC 9899: 2011).

Puede omitir el error del comstackdor al refundirlo como char* , como en *((char*)s + 1) = 'a'; pero como ya se estableció en otras respuestas, este es un comportamiento indefinido y probablemente dará lugar a una falla de segmentación porque está editando un literal de cadena.

Si desea probarlo correctamente, inicialice las cadenas en una función para que la inicialización sea dinámica y use strdup() para eso.

 int main(int argc, char **argv) { char *d1 = strdup("hello"); char *d2 = strdup("world"); const char *s = d1; char *const t = d2; ... free(d1); free(d2); } 

Las variables d1 y d2 se utilizan principalmente para que las asignaciones dinámicas se puedan liberar de forma apropiada utilizando free() al final. Además, como sugieren otras respuestas, siempre trate los literales de cadena como const char * .