Observa el siguiente código:
const char *str1 = "foo"; printf("1.1: %s\n", str1); str1 = "bar"; printf("1.2: %s\n\n", str1); const char *str2[] = { "foo", "bar" }; printf("2.1: %s\n", str2[0]); str2[0] = "baz"; printf("2.2: %s\n\n", str2[0]); char *str3 = malloc(4); strcpy(str3, "foo"); const char *str4[] = { str3, "bar" }; printf("3.1: %s -- %s\n", str4[0], str4[1]); //str4[0][0] = 'z'; str4[0] = "bar"; str4[1] = "baz"; printf("3.2: %s -- %s\n", str4[0], str4[1]); free(str3); Envolviéndolo en una función main estándar y compilando con gcc -Wall -Wextra -o test test.c , esto no da advertencias y el resultado es:
1.1: foo 1.2: bar 2.1: foo 2.2: baz 3.1: foo -- bar 3.2: bar -- baz Al descomentar la única línea comentada, gcc se queja error: assignment of read-only location '*str4[0]' . Por supuesto, esto es de esperar, solo agregué ese bit para completar.
Según tengo entendido, todas las demás asignaciones son válidas porque no estoy modificando la memoria de solo lectura ya existente, la estoy reemplazando en su totalidad con otro bloque de memoria (que luego también está marcado como de solo lectura). Pero, ¿es esto legal en todos los compiladores de C, o todavía depende de la implementación y, por lo tanto, puede dar como resultado un comportamiento indefinido? Es un poco difícil encontrar buena información sobre esto porque siempre parece tratarse de modificar la memoria existente a través de la magia del puntero o desechar la const .
En esta declaración
const char *str1 = "foo"; el puntero (variable) str1 no es constante. Es el literal de cadena apuntado por el puntero str1 que es constante. Ese es el puntero (no constante) str1 apunta a un objeto constante del tipo const char .
Por lo tanto, no puede cambiar el literal al que apunta el puntero, como por ejemplo
str1[0] = 'g'; Pero puede cambiar la variable str1 porque no es constante
str1 = "bar"; Para declarar el puntero str1 como un puntero constante, debe escribir
const char * const str1 = "foo";En este caso no puede escribir
str1 = "bar"; Porque ahora el puntero str1 en sí mismo es constante.
Tenga en cuenta que, aunque en C, los literales de cadena tienen tipos de matrices de caracteres no constantes, sin embargo, no puede cambiar un literal de cadena. Cualquier intento de cambiar un literal de cadena da como resultado un comportamiento indefinido.
Eso es que no puedes escribir
char *str1 = "foo"; str1[0] = 'g';