2011-12-22 21 views
21

Me preguntaba por qué el siguiente código de trabajo isnt'tAsignar memoria y guardar cadena en C

int main(int argc, char **argv) 
{ 
    char *test = (char*) malloc(12*sizeof(char)); 
    test = "testingonly"; 
    free(test); 
} 

Después de pensarlo mi suposición era que primero asignar espacio para 12 caracteres en la memoria pero la asignación en el La siguiente línea crea una matriz char en la pila y la dirección de la memoria se pasa a prueba. Entonces free() intenta liberar espacio en la pila que no está permitido. ¿Es eso correcto?

Entonces, ¿cuál sería el enfoque correcto para guardar una cadena en el montón? ¿Es la siguiente una forma común?

int main(int argc, char **argv) 
{ 
    char *test = (char*) malloc(12*sizeof(char)); 
    strcpy(test, "testingonly"); 
    free(test); 
} 
+4

La primera solución ilustra una fuga de memoria clásica; obtienes un puntero a la memoria asignada, y luego pierdes la única referencia cuando asignas el puntero al literal de la cadena para 'test'. A partir de entonces, no hay una forma legítima para que usted haga referencia a la memoria asignada, una fuga. –

+2

Nunca modifique el resultado de malloc en C, no tiene sentido y solo oculta los errores y las advertencias del compilador. – Lundin

+2

sí - use 'strcpy' o' strncpy' o 'memcpy'. strncpy es mejor que strcpy, porque ayuda a evitar el problema de desbordamiento del búfer mientras se copia con un máximo de N caracteres. –

Respuesta

8

Usted ya ha respondido a su pregunta. Básicamente, strcpy es la forma adecuada de copiar cadenas.

+0

Siempre que sepa que la memoria adecuada ya ha sido asignada en la cadena de destino, y ambas cadenas tienen terminación nula. – Dave

5

La primera versión no crea una cadena en la pila, pero está en lo cierto de que no se le permite free después de la asignación. Los literales de cadena generalmente se almacenan en secciones de memoria constante/de solo lectura. La asignación no copia nada, solo hace que test señale esa área de memoria. No puedes liberarlo. Tampoco puedes modificar esa cadena.

Su segundo código es correcto y habitual. Es posible que también desee consultar strdup si su implementación tiene eso.

+0

+1 para secciones constantes/de solo lectura –

+0

'strncpy' es * no * una versión más segura de' strcpy'. Puede dejar la matriz de destino sin terminar. Rara vez es la solución correcta. –

+0

@Keith: a la derecha, se eliminó la referencia a esa. 'strdup' es bastante agradable (suponiendo que usted sabe que su entrada es 1. una cadena C válida y 2. de tamaño aceptable, lo que sea que sea para su aplicación). – Mat

4

Bueno, estás en lo cierto. Ahora examinemos la primera pieza de código.

char *test = (char*) malloc(12*sizeof(char)); 

El código de arriba no es un problema.

test = "testingonly"; 

Aquí modificó el puntero test que conduce a pérdida de memoria. Y cuando intenta liberar, no está liberando el puntero real asignado, sino un literal que apunta "solo a prueba". Literal apunta a la memoria constante que no puede ser anulada en los escenarios habituales.

Ahora, sobre la segunda parte del código, esto funcionará bien ya que copió explícitamente los datos de donde literal está residiendo en el montón donde apunta su test.

Para su segundo punto sí strcpy es una forma habitual. Otras formas son 'memcpy' si está copiando bytes sin formato.

NOTA: Literals no se almacenan en la pila. Pero no puede modificar la ubicación donde se almacenan los literales.

+0

+1 para "esto funcionará bien ya que copió explícitamente los datos de donde literal reside en el montón al que apunta su prueba" –

57
char *test = (char*) malloc(12*sizeof(char)); 

     +-+-+-+-+-+-+-+-+-+-+-+-+ 
test--->|x|x|x|x|x|x|x|x|x|x|x|x| (uninitialized memory, heap) 
     +-+-+-+-+-+-+-+-+-+-+-+-+ 

test = "testingonly"; 

     +-+-+-+-+-+-+-+-+-+-+-+-+ 
test + |x|x|x|x|x|x|x|x|x|x|x|x| 
    | +-+-+-+-+-+-+-+-+-+-+-+-+ 
    | +-+-+-+-+-+-+-+-+-+-+-+-+ 
    +->|t|e|s|t|i|n|g|o|n|l|y|0| 
     +-+-+-+-+-+-+-+-+-+-+-+-+ 

free(test); // error, because test is no longer pointing to allocated space. 

En lugar de cambiar el puntero test, es necesario copiar la cadena "testingonly" en el lugar asignado usando, por ejemplo, strcpy o use strdup. Tenga en cuenta que las funciones como malloc y strdup devuelven NULL si hay memoria insuficiente disponible y, por lo tanto, deben verificarse.

char *test = (char*) malloc(12*sizeof(char)); 
strcpy(test, "testingonly"); 

     +-+-+-+-+-+-+-+-+-+-+-+-+ 
test--->|t|e|s|t|i|n|g|o|n|l|y|0| 
     +-+-+-+-+-+-+-+-+-+-+-+-+ 

o

char *test = strdup("testingonly"); 

     +-+-+-+-+-+-+-+-+-+-+-+-+ 
test--->|t|e|s|t|i|n|g|o|n|l|y|0| 
     +-+-+-+-+-+-+-+-+-+-+-+-+ 
+4

+1 aprecia su esfuerzo al explicarlo. – dicaprio

+0

gracias !!!! estupendo –

0

el código

#include <stdio.h> 
int main(int argc, char **argv) 
{ 
    char *test = (char*) malloc(12*sizeof(char)); 
    strcpy(test, "testingonly"); 
    printf("string is: %s\n",test); 
    free(test); 
    return 0; 
} 

funcionará

0

Esto es para la asignación de la memoria:

char *string; 
string = (char *) malloc(15); 

Esto es para guardar los datos:

strcpy(str, "kavitajain"); 
printf("String = %s, Address = %u\n", str, str); 
Cuestiones relacionadas