2009-12-26 28 views
83

Entiendo cómo funciona malloc(). Mi pregunta es, voy a ver cosas como esta:¿Cuándo debo usar malloc en C y cuándo no?

#define A_MEGABYTE (1024 * 1024) 

char *some_memory; 
size_t size_to_allocate = A_MEGABYTE; 
some_memory = (char *)malloc(size_to_allocate); 
sprintf(some_memory, "Hello World"); 
printf("%s\n", some_memory); 
free(some_memory); 

omití la comprobación de errores en aras de la brevedad. Mi pregunta es, ¿no puede hacer lo anterior inicializando un puntero a algún almacenamiento estático en la memoria? quizá:

char *some_memory = "Hello World"; 

¿En qué momento es lo que realmente necesitan para asignar la memoria a sí mismo en lugar de declarar/inicializar los valores que necesita para retener?

+4

Re: * Me omite la comprobación de errores en aras de la brevedad * - por desgracia demasiados programadores * * omitir la comprobación de errores, ya que no se dan cuenta de 'malloc()' puede fallar! – Andrew

Respuesta

114
char *some_memory = "Hello World"; 

está creando un puntero a una constante de cadena. Eso significa que la cadena "Hello World" estará en algún lugar de la parte de solo lectura de la memoria y que solo tiene un puntero a ella. Puede usar la cadena como de solo lectura. Usted no puede hacer cambios en él. Ejemplo:

some_memory[0] = 'h'; 

Está pidiendo problemas.

Por otro lado

some_memory = (char *)malloc(size_to_allocate); 

es la asignación de una matriz de caracteres (una variable) y puntos some_memory a la memoria asignada. Ahora esta matriz es tanto de lectura como de escritura. Ahora puede hacer:

some_memory[0] = 'h'; 

y contenido de la matriz cambia a "Hello World"

+15

Solo para aclarar, tanto como me gusta esta respuesta (le di +1), puede hacer lo mismo sin malloc() simplemente usando una matriz de caracteres. Algo así como: char some_memory [] = "Hello"; some_memory [0] = 'W'; también funcionará – randombits

+14

Tienes razón. Usted puede hacer eso. Cuando utiliza malloc() la memoria se asigna dinámicamente en tiempo de ejecución, por lo que no necesita reparar el tamaño de la matriz en tiempo de compilación también puede hacerlo crecer o contraerse usando realloc(). Ninguna de estas cosas se puede hacer cuando lo hace: char some_memory [] = "Hola"; Aquí, aunque puede cambiar el contenido de la matriz, su tamaño es fijo. Por lo tanto, dependiendo de sus necesidades, utilice cualquiera de las tres opciones: 1) puntero a char const 2) matriz dinámicamente asignada 3) tamaño fijo, matriz asignada en tiempo de compilación. – codaddict

+0

Para enfatizar que es de solo lectura, debe escribir 'const char * s =" hi ";' ¿No es esto realmente requerido por el estándar? –

4

Un motivo cuando es necesario asignar la memoria es si desea modificarla en tiempo de ejecución. En ese caso, se puede usar un malloc o un buffer en la pila. El simple ejemplo de asignar "Hello World" a un puntero define la memoria que "normalmente" no se puede modificar en el tiempo de ejecución.

27

Para ese ejemplo exacto, malloc es de poca utilidad.

La razón principal por la que se necesita malloc es cuando tiene datos que deben tener una duración de vida que es diferente del alcance del código. Su código llama a malloc en una rutina, almacena el puntero en algún lugar y, finalmente, llama gratis en una rutina diferente.

Una razón secundaria es que C no tiene forma de saber si queda espacio suficiente en la pila para una asignación. Si su código necesita ser 100% robusto, es más seguro usar malloc porque entonces su código puede saber que la asignación falló y manejarlo.

+2

ciclos de vida de la memoria, y la cuestión conexa de cuándo y cómo cancelar la asignación ella, son un problema importante con muchas bibliotecas comunes y componentes de software. Por lo general tienen una regla bien documentada: "Si pasa un puntero a esta * * una de mis rutinas, es necesario tener malloc'd que voy a seguir la pista de ella, y liberarla cuando he terminado con. eso." Una fuente común de errores desagradables es pasar un puntero a la memoria asignada de forma estática a una biblioteca de este tipo. Cuando la biblioteca intenta liberarlo(), el programa falla. Recientemente, pasé mucho tiempo solucionando un error como el que escribió otra persona. –

+0

¿Estás diciendo que la única vez que malloc() se utiliza en la práctica, es cuando hay un segmento de código que se llama varias veces durante la vida del programa que se llama varias veces y necesitan ser 'limpiado', ya malloc() va acompañado de free()? Por ejemplo, en un juego como rueda de la fortuna, donde después de adivinar, y poner la entrada en una matriz de caracteres designado, que el malloc() - matriz de tamaño puede ser liberado para la siguiente conjetura? –

+0

La vida útil de los datos es realmente la verdadera razón para usar malloc. Supongamos que un tipo de datos abstracto está representado por un módulo, declara un tipo de lista y rutinas para agregar/eliminar elementos de la lista.Esos valores de los elementos, necesitan copiarse en la memoria asignada dinámicamente. – Rob11311

5
char *some_memory = "Hello World"; 
sprintf(some_memory, "Goodbye..."); 

es ilegal, literales de cadena son const.

Esto asignará una matriz de caracteres de 12 bytes en la pila o globalmente (dependiendo de dónde se haya declarado).

char some_memory[] = "Hello World"; 

Si desea dejar espacio para una mayor manipulación, puede especificar que la matriz debe ser de mayor tamaño. (Por favor, no ponga 1 MB en la pila, sin embargo.)

#define LINE_LEN 80 

char some_memory[LINE_LEN] = "Hello World"; 
strcpy(some_memory, "Goodbye, sad world..."); 
printf("%s\n", some_memory); 
14

malloc es una maravillosa herramienta para la asignación, reasignación y liberación de memoria en tiempo de ejecución, en comparación con las declaraciones estáticas como el ejemplo del mundo hola, que se procesan en tiempo de compilación y, por lo tanto, no puede cambiarse de tamaño.

Malloc es, por lo tanto, siempre útil cuando se trata de datos de tamaño arbitrario, como leer contenidos de archivos o tratar con sockets y no conoce la longitud de los datos para procesar.

Por supuesto, en un ejemplo trivial como el que dio, malloc no es la "herramienta correcta mágica para el trabajo correcto", pero para casos más complejos (creando una matriz de tamaño arbitrario en tiempo de ejecución por ejemplo), es el único camino a seguir.

3

Si usted no sabe el tamaño exacto de la memoria es necesario utilizar, necesita la asignación dinámica (malloc) . Un ejemplo podría ser cuando un usuario abre un archivo en su aplicación. Tendrá que leer el contenido del archivo en la memoria, pero, por supuesto, no conoce el tamaño del archivo por adelantado, ya que el usuario selecciona el archivo en el momento, en tiempo de ejecución. Entonces, básicamente necesita malloc cuando no conoce el tamaño de los datos con los que está trabajando por adelantado. Al menos esa es una de las razones principales para usar malloc. En su ejemplo, con una cadena simple que ya conoce el tamaño en tiempo de compilación (además de que no desea modificarla), no tiene mucho sentido asignarla dinámicamente.


poco fuera de tema, pero ... hay que tener mucho cuidado de no crear pérdidas de memoria cuando se utiliza malloc. Considere este código:

int do_something() { 
    uint8_t* someMemory = (uint8_t*)malloc(1024); 

    // Do some stuff 

    if (/* some error occured */) return -1; 

    // Do some other stuff 

    free(someMemory); 
    return result; 
} 

¿Ve qué le pasa a este código? Hay una declaración de devolución condicional entre malloc y free. Puede parecer correcto al principio, pero piénselo. Si hay un error, vas a regresar sin liberar la memoria que asignaste. Esta es una fuente común de pérdidas de memoria.

Por supuesto, esto es un ejemplo muy simple, y es muy fácil de ver el error aquí, pero imagina cientos de líneas de código llenas de punteros, malloc s, free s, y todo tipo de control de errores. Las cosas pueden ponerse realmente desordenadas muy rápido. Esta es una de las razones por las que prefiero el C++ moderno en lugar de C en los casos aplicables, pero ese es otro tema.

Por lo tanto, siempre que use malloc, siempre asegúrese de que su memoria sea lo más probable sea free d como sea posible.

Cuestiones relacionadas