varias signo operadores not graficas google funciona filetype como comandos comando caracteres busquedas busqueda avanzadas avanzada and c string pointers memory

signo - ¿Cómo pueden diferentes cadenas tener la misma dirección



operadores de busqueda (7)

Esta pregunta ya tiene una respuesta aquí:

Sé que para comparar dos cadenas en C, necesitas usar la función strcmp() . Pero traté de comparar dos cadenas con el operador == , y funcionó. No sé cómo, porque solo compara la dirección de las dos cadenas. No debería funcionar si las cuerdas son diferentes. Pero luego imprimí la dirección de las cuerdas:

#include <stdio.h> #include <stdlib.h> int main() { char* str1 = "First"; char* str2 = "Second"; char* str3 = "First"; printf("%p %p %p", str1, str2, str3); return 0; }

Y la salida fue:

00403024 0040302A 00403024 Process returned 0 (0x0) execution time : 0.109 s Press any key to continue.

¿Cómo es posible que str1 y str3 tengan la misma dirección? Pueden contener la misma cadena, pero no son la misma variable.


Cuando un literal de cadena particular aparece varias veces en un archivo fuente, el compilador puede elegir tener todas las instancias de ese punto literal en el mismo lugar.

La sección 6.4.5 de la norma C , que describe los literales de cadena, establece lo siguiente:

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

Donde "comportamiento no especificado" se define en la sección 3.4.4 como:

uso de un valor no especificado u otro comportamiento donde esta Norma Internacional proporciona dos o más posibilidades y no impone requisitos adicionales sobre los que se elija en cualquier caso

En su caso, la cadena literal "First" aparece dos veces en la fuente. Así que el compilador usa la misma instancia del literal para ambos, lo que resulta en que str1 y str3 apuntan a la misma instancia.

Como se indicó anteriormente, este comportamiento no está garantizado. Las dos instancias de "First" podrían ser distintas entre sí, lo que resultaría en que str1 y str3 apuntan a diferentes lugares. No se especifica si dos instancias idénticas de un literal de cadena residen en el mismo lugar.


Es porque todas las cadenas codificadas como "Primero" y "Segundo" están presentes en la parte "ejecutable" del ejecutable, por lo tanto, tienen una dirección.

En linux, puede verlos usando "objdump -s -j .rodata execfile".

Si intenta mostrar las direcciones str1, str2 y str3, verá que hay diferentes.


Hay un punto interesante aquí. Lo que tienes en realidad son solo 3 puntos, todos apuntando a cadenas constantes . Así que el compilador es libre de crear una sola cadena para "First" y tener ambos puntos str1 y str3 allí.

Este sería un caso completamente diferente:

char str1[] = "First"; char str2[] = "Second"; char str3[] = "First";

He declarado 3 matrices de caracteres diferentes inicializadas a partir de cadenas literales. Pruébelo, y verá que el compilador ha asignado diferentes direcciones para las 3 cadenas diferentes.

Lo que debe recordar de eso: los punteros y las matrices son animales diferentes, incluso si las matrices pueden decaer a los punteros (más sobre esto en esta publicación de la sección de Preguntas frecuentes de C )


La razón por la que esto es tan desconcertante podría ser: "Pero, ¿qué sucede si configuro str1[1] = ''u''; ? ”Ya que está definido por la implementación si str1 == str3 (y si la dirección del literal "world!" Es la dirección de "hello, world!" Más 7), ¿eso aldo convierte a str3 en un príncipe alemán?

La respuesta es: tal vez. O tal vez solo cambia str1 , o tal vez falla silenciosamente en cambiar, o tal vez bloquea el programa porque escribiste en la memoria de solo lectura, o tal vez causa algún otro error sutil porque reutilizó esos bytes para otro propósito. , o algo completamente distinto.

El hecho de que incluso se puede asignar un literal de cadena a un char* , en lugar de tener que usar const char* , es básicamente un cambio por el código heredado de décadas de antigüedad. Las primeras versiones de C no tenían const . Algunos compiladores existentes permiten que los programas cambien las constantes de cadena y otros no. Cuando el comité de estándares decidió agregar la palabra clave const de C ++ a C, no estaban dispuestos a romper todo ese código, por lo que dieron permiso a los compiladores para hacer básicamente cualquier cosa cuando un programa cambia una cadena literal.

La implicación práctica de esto es: nunca asigne un literal de cadena a un char* que no sea const . Y nunca asuma que las constantes de cadena se superponen o no (a menos que garantice esto con restrict ). Ese tipo de código ha sido obsoleto desde 1989, y solo te permite dispararte en el pie. Si desea un puntero a una cadena literal (que puede o no compartir memoria con otras constantes), guárdelo en const char* o, mejor aún, const char* const . Eso te avisa si intentas modificarlo. Si desea una matriz de caracteres que se puede modificar (y se garantiza que no se asigne alias a ninguna otra variable), guárdela en un char[] .

Si crees que quieres comparar cadenas por sus direcciones, lo que realmente quieres es un valor hash o un identificador único.


Los literales de cadena, al igual que los literales compuestos C99 +, pueden agruparse. Eso significa que dos ocurrencias diferentes en el código fuente pueden de hecho resultar en una sola instancia en el programa en ejecución.
Ese incluso podría ser el caso si su objetivo no es compatible con la protección contra escritura del hardware.


No hay garantía de que siempre será así. En general, los implementadores mantienen un grupo literal que mantiene cada uno de los literales de cadena una sola vez, y luego, para usos múltiples de la cadena literal, se utiliza la misma dirección. Pero uno podría implementarlo de una manera diferente: el estándar no supone una restricción para esto.

Ahora su pregunta: usted está mirando el contenido de los dos punteros que apuntan a la misma cadena literal. El mismo literal de cadena dio lugar al mismo valor (decayeron en un puntero al primer elemento). Pero esa dirección es la misma por la razón indicada en el primer párrafo.

También, enfatizaría en proporcionar el argumento del especificador de formato %p con la (void*) .


Para agregar a las otras respuestas: esta es una técnica llamada internado de cadenas donde el compilador se da cuenta de que las cadenas son las mismas y, por lo tanto, solo las almacena una vez. Java también tiende a hacer esto (aunque, como lo menciona el otro póster, depende del compilador).