2009-06-03 16 views
5

Con cadenas estilo c, ¿cómo se asigna un carácter a una dirección de memoria a la que apunta un puntero de carácter? Por ejemplo, en el ejemplo siguiente, quiero cambiar num a "123456", así que intenté establecer p en el dígito donde está ubicado '0' e intento sobrescribirlo con '4'. Gracias.¿Por qué este código para modificar una cadena no funciona?

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    char* num = (char*)malloc(100); 
    char* p = num; 

    num = "123056"; 

    p = p+3; //set pointer to where '4' should be 
    p = '4'; 

    printf("%s\n", num); 

    return 0; 
} 
+0

duplicado posible de [¿Por qué aparece un fallo de segmentación al escribir a una cadena inicializado con "char \ * s", pero no "char s \ [\]"? ] (http://stackoverflow.com/questions/164194/why-do-i-get-asegmentation-fault-when-writing-to-a-string-initialized-with-cha) – jww

Respuesta

12

Ese código no funcionará, simplemente porque la línea:

num = "123056"; 

cambia num a apuntar hacia afuera de la memoria asignada (y sigue siendo p que apunta a la memoria de modo que ya no son la misma ubicación) a lo que probablemente sea la memoria de solo lectura. No está permitido cambiar la memoria que pertenece a los literales de cadena, es un comportamiento indefinido.

Es necesario lo siguiente:

#include <stdio.h> 
#include <stdlib.h> 
int main (void) { 
    char *num = malloc (100); // do not cast malloc return value. 
    char *p = num; 

    strcpy (num, "123056"); // populate existing block with string. 

    p = p + 3;    // set pointer to where '0' is. 
    *p = '4';     // and change it to '4'. 

    printf ("%s\n", num); // output it. 

    return 0; 
} 
+0

Además, necesita liberar la memoria. –

+2

Esa es una buena forma, @Igor, pero no es necesario dado que el programa se está cerrando de inmediato. Y la idea de un fragmento es transmitir información relevante, no toda la información, de lo contrario, debemos verificar que el malloc() funcionó también. – paxdiablo

0

Solo use *p = '4'; ...!

+0

Desreferenciando no lo hizo trabajo. ¿La cadena 'num' es inmutable o algo así? Estoy compilando con cc en linux. –

+0

Esto está mal; debe ser '4', no 4. –

+0

Sí, es probable que el literal de la cadena esté asignado en una memoria segent que está marcada como de solo lectura y cualquier intento de escribir en ella provoca un error de tiempo de ejecución. – sharptooth

13

En primer lugar, cuando lo hace:

num = "123056"; 

No está copiando la cadena "123056" a la zona del montón asignado por malloc(). En C, la asignación de un puntero char * un valor literal de cadena es equivalente a establecer como una constante - es decir, idéntica a:

char str[] = "123056"; 

Por lo tanto, lo que acaba has logrado no has abandonado su única referencia a la Área de almacenamiento de 100 bytes asignada por malloc(), por lo que su código posterior no imprime el valor correcto; 'p' todavía apunta al área de pila asignada por malloc() (ya que num lo señaló en el momento de la asignación), pero num ya no lo hace.

Supongo que en realidad tenía la intención de hacer era copiar la cadena "123056" en esa área del montón. He aquí cómo hacerlo:

strcpy(num, "123056"); 

Aunque, esto es mejor práctica para una variedad de razones:

strncpy(num, "123056", 100 - 1); /* leave room for \0 (null) terminator */ 

Si acababa de hacer:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int  main(void) { 
     char *num = malloc(100); 
     char *p = num; 

     strncpy(num, "123056", 100 - 1); 

     p = p + 3; 
     *p = '4'; 

     printf("%s\n", num); 

     return 0; 
} 

Usted habría conseguido la resultado correcto:

123456 

Usted puede contraer esta operación:

p = p + 3; 
*p = '4'; 

... y evitar la iteración del puntero, por deferencing de la siguiente manera:

*(p + 3) = '4'; 

Algunas otras notas:

  • Aunque estilística común práctica, arrojar el valor de retorno de malloc() a (char *) es innecesario. La conversión y alineación del tipo void * está garantizada por el lenguaje C.

  • SIEMPRE verifique el valor de retorno de malloc(). Será NULO si la asignación del montón falló (es decir, no tiene memoria) y en ese punto su programa debería salir.

  • Dependiendo de la implementación, el área de memoria asignada por malloc() puede contener basura obsoleta en ciertas situaciones.Siempre es una buena idea para poner a cero a cabo después de la asignación:

    memset(num, 0, 100); 
    
  • nunca se olvide de free() su montón! En este caso, el programa se cerrará y el sistema operativo limpiará su basura, pero si no adquiere el hábito, tendrá pérdidas de memoria en muy poco tiempo.

Por lo tanto, aquí está la "mejor práctica" versión:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int  main(void) { 
     char *num, *p; 

     /* 
     * Don't take 1-byte chars for granted - good habit to get into. 
     */ 

     num = malloc(sizeof(char) * 100); 

     if(num == NULL) 
       exit(1); 

     memset(num, 0, sizeof(char) * 100); 

     p = num; 

     strncpy(num, "123056", 100 - 1); 

     *(p + 3) = '4'; 

     printf("%s\n", num); 

     free(num); 

     return 0; 
} 
+1

Gracias por los excelentes consejos de administración de memoria. ¡Estos consejos son buenos para las personas que provienen de los lenguajes de recolección automática de basura! –

+0

¡Claro! ¡Feliz de ayudar! –

+0

¡Excelente publicación! Mucha información valiosa Gracias. –

0

bueno, ya sabes p es un tipo de puntero. Almacena la dirección de char '0'. Si asigna p el valor de '4'. Tomará '4' como la dirección. Sin embargo, la dirección '4' es ilegal. Puede usar el operador '*' para obtener el valor de la dirección almacenada en p almacenada.

+0

Un nitpick, la dirección '4' no es ilegal. Las implementaciones pueden usar fácilmente la memoria en 0x00000034 (incluso está alineada correctamente para una palabra de 32 bits). – paxdiablo

+0

Bueno, dije ilegal para esta aplicación. Es una dirección de memoria desconocida. – Sefler

1

Además del problema * p que otros han señalado, también tiene problemas de uso de memoria. Tienes un buffer de 100 bytes, con contenido desconocido. Tiene otro búfer de 7 bytes, que contiene la cadena "123056" y un terminador nulo. Estás haciendo esto:

  1. num se establece en el punto en el búfer de 100 bytes
  2. p se establece para que apunte a num; es decir, apunta a la memoria intermedia de 100 bytes
  3. que restablece num para apuntar a la memoria intermedia de 7 bytes; p todavía está apuntando a la memoria intermedia 100 bytes
  4. Utilice p para modificar el buffer de 100 bytes
  5. continuación, utiliza num para imprimir el buffer de 7 bytes

Por lo que no está imprimiendo el mismo tampón que estás modificando

+0

Gracias, Bruce, tu explicación fue útil, pero Strcpy de Pax realmente lo dejó en claro. –

Cuestiones relacionadas