Pregunta

Tengo el siguiente código:

#include <iostream>
using namespace std;
int main()
{
    char* a = "foo";
    char* b = "bar";
    a = b;
    cout << a << ", " << b << endl;
    return 0;
}

Esto compila y funciona, es decir.huellas dactilares bar, bar.Ahora me gustaría demostrar que lo que sucede aquí no es copiar una cadena.me gustaría cambiar b y demostrar que a también cambia.Se me ocurrió este código simple:

#include <iostream>
using namespace std;
int main()
{
    char* a = "foo";
    char* b = "bar";
    a = b;
    b[1] = 'u'; // ← just this line added
    cout << a << ", " << b << endl;
    return 0;
}

…pero tiene un error de segmentación.¿Por qué?Lo interesante es que la siguiente modificación funciona bien:

#include <iostream>
using namespace std;
int main()
{
    char* a = "foo";
    char b[] = "bar"; // ← declaration changed here
    a = b;
    b[1] = 'u';
    cout << a << ", " << b << endl;
    return 0;
}

¿Por qué no segmenta como el anterior?Supongo que me falta alguna diferencia importante entre la inicialización de cadena de estilo puntero y estilo matriz.

¿Fue útil?

Solución

No puede cambiar las constantes de cadena, que es lo que obtiene cuando usa la sintaxis de puntero a literal como en las primeras muestras de código.

Consulte también esta pregunta: es un literal de cadena en c ++ creado en memoria estática? .

Otros consejos

Cuando escribes esto:

char *b = "bar";

el compilador asigna un área de memoria anónima (sin nombre) para almacenar la cadena literal " bar " ;. Los literales de cadena no pueden modificarse, por lo que el compilador (con la ayuda del enlazador y el sistema operativo) coloca el literal de cadena en una parte del espacio de memoria del programa en ejecución que está protegido contra escritura. Cuando intenta modificarlo, el sistema operativo lo detecta y hace que su programa falle en la segmentación.

(Su código es C ++, no C, pero eso es irrelevante para esta pregunta).

Cuando escribes:

char *foo = "bar";

Lo que realmente sucede es que la " bar " se almacena en el segmento de memoria de solo lectura. Por lo tanto, es inmutable. Obtiene un segfault porque intenta modificar un segmento de solo lectura.

También puede mostrar que 'a' ha cambiado imprimiendo el valor del puntero.

#include <iostream>
using namespace std;
int main()
{
    char* a = "foo";
    char* b = "bar";
    a = b;

    cout << (void*)a << ", " << (void*)b << endl;
}

Esto imprimirá la dirección a la que apuntan 'a' y 'b'.
Tienes que lanzar a 'void *' porque el operador & Lt; & Lt; está sobrecargado para 'char *' para imprimir la cadena; cualquier otro puntero imprimirá la dirección.

En teoría, un literal de cadena no debería poder asignarse a un char *, solo a 'const char *'. Entonces el compilador lo detendría antes de que escribiera el código de falla seg.

Esta diferencia es quizás específica del compilador. Para demostrar su punto, use malloc para asignar el búfer, luego copie la cadena en este búfer y no olvide usar free cuando ya no necesite la cadena.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top