C: diferencias entre puntero char y matriz [duplicado]
Considerar:
char amessage[] = "now is the time";
char *pmessage = "now is the time";
Leí en The C Programming Language , segunda edición, que las dos declaraciones anteriores no hacen lo mismo.
Siempre pensé que una matriz es una forma conveniente de manipular punteros para almacenar algunos datos, pero claramente este no es el caso... ¿Cuáles son las diferencias "no triviales" entre matrices y punteros en C?
Aquí hay un mapa de memoria hipotético que muestra los resultados de las dos declaraciones:
0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
0x00008000: 'n' 'o' 'w' ' ' 'i' 's' ' ' 't'
0x00008008: 'h' 'e' ' ' 't' 'i' 'm' 'e' '\0'
...
amessage:
0x00500000: 'n' 'o' 'w' ' ' 'i' 's' ' ' 't'
0x00500008: 'h' 'e' ' ' 't' 'i' 'm' 'e' '\0'
pmessage:
0x00500010: 0x00 0x00 0x80 0x00
La cadena literal "ahora es el momento" se almacena como una matriz de caracteres de 16 elementos en la dirección de memoria 0x00008000. Es posible que no se pueda escribir en esta memoria; lo mejor es asumir que no lo es. Nunca debes intentar modificar el contenido de una cadena literal.
La declaracion
char amessage[] = "now is the time";
asigna una matriz de 16 elementos de caracteres en la dirección de memoria 0x00500000 y copia el contenido de la cadena literal en ella. Esta memoria se puede escribir; Puedes cambiar el contenido de un mensaje al contenido de tu corazón:
strcpy(amessage, "the time is now");
La declaracion
char *pmessage = "now is the time";
asigna un único puntero a char en la dirección de memoria 0x00500010 y le copia la dirección de la cadena literal.
Dado que pmessage apunta al literal de cadena, no debe usarse como argumento para funciones que necesitan modificar el contenido de la cadena:
strcpy(amessage, pmessage); /* OKAY */
strcpy(pmessage, amessage); /* NOT OKAY */
strtok(amessage, " "); /* OKAY */
strtok(pmessage, " "); /* NOT OKAY */
scanf("%15s", amessage); /* OKAY */
scanf("%15s", pmessage); /* NOT OKAY */
etcétera. Si cambió pmessage para que apunte a un mensaje :
pmessage = amessage;
entonces se puede utilizar en todos los lugares donde se pueda utilizar un mensaje .
Es cierto, pero es una diferencia sutil. Esencialmente, lo primero:
char amessage[] = "now is the time";
Define una matriz cuyos miembros viven en el espacio de pila del alcance actual, mientras que:
char *pmessage = "now is the time";
Define un puntero que reside en el espacio de pila del alcance actual, pero que hace referencia a la memoria en otro lugar (en este, "ahora es el momento" se almacena en otro lugar de la memoria, comúnmente una tabla de cadenas).
Además, tenga en cuenta que debido a que los datos que pertenecen a la segunda definición (el puntero explícito) no se almacenan en el espacio de pila del alcance actual, no se especifica exactamente dónde se almacenarán y no se deben modificar.
Como señalaron Mark, GMan y Pavel, también hay una diferencia cuando se utiliza el operador de dirección en cualquiera de estas variables. Por ejemplo, &pmessage devuelve un puntero de tipo char**, o un puntero a un puntero a caracteres, mientras que &amessage devuelve un puntero de tipo char(*)[16], o un puntero a una matriz de 16 caracteres (que, como un char**, debe eliminarse la referencia dos veces como señala litb).