Asignación dinámica de memoria en C

La asignación dinámica de memoria en el Lenguaje de programación C, conocida también como malloc (abreviatura del inglés memory allocation), se realiza a través de un grupo de funciones en la biblioteca estándar de C , es decir, malloc , realloc , calloc y free . En C++, se incluyen estas funciones por retrocompatibilidad, pero han sido sustituidas en gran parte por los operadores new y new[].

Están disponibles muchas implementaciones diferentes del mecanismo de asignación de memoria real, utilizado por malloc . Su rendimiento varía tanto en tiempo de ejecución y memoria requerida.

Fundamento

El lenguaje de programación C gestiona la memoria de forma estática, automática o dinámica. Las variables estáticas se asignan en la memoria principal, por lo general junto con el código ejecutable del programa, y persisten durante toda la vida del programa; las variables automáticas se asignan sobre la pila (stack), comienzan cuando se invocan las funciones y acaban cuando se llama a return. Para las variables estáticas y automáticas se requiere que el tamaño de la asignación sea constante en tiempo de compilación (antes de C99 , que permite "arrays" automáticos de longitud variable). Si el tamaño requerido no se conoce hasta el tiempo de ejecución (por ejemplo, si los datos de tamaño arbitrario se están leyendo del usuario o desde un archivo de disco), la utilización de objetos de datos de tamaño fijo es insuficiente.

La vida útil de la memoria asignada es también una preocupación. Ni la memoria estática ni automática es adecuada para todas las situaciones. Los datos automáticos asignados no persisten en varias llamadas de función, mientras que los datos estáticos persisten durante toda la vida del programa, sean o no necesarios. En muchas situaciones, el programador requiere una mayor flexibilidad en la gestión de la vida útil de la memoria asignada.

Estas limitaciones se evitan mediante el uso de la gestión de memoria en la que la memoria es más explícitamente (y más flexiblemente) manejada, típicamente mediante la asignación desde el montón (heap), un área de memoria estructurada para este fin. En C, la función malloc, perteneciente a la cabecera stdlib.h, se utiliza para asignar un bloque de memoria en el montón. El programa accede a este bloque de memoria a través de un puntero que malloc regresa. Cuando ya no se necesita la memoria, se pasa el puntero a la función free, la cual libera la memoria de modo que se puede utilizar para otros fines.

Algunas plataformas ofrecen llamadas de biblioteca que permiten en tiempo de ejecución la asignación dinámica de la pila C en lugar de la pila (por ejemplo Unix alloca(), Microsoft Windows de CRTL malloca() ). Esta memoria se libera automáticamente cuando la función de llamada termina. La necesidad de este se ve reducida por los cambios en el estándar C99, que añade soporte para arrays de longitud variable de ámbito de bloque que tienen tamaños que determine en tiempo de ejecución.

Resumen de las funciones

Las funciones de asignación de memoria dinámica en C se definen en la cabecera stdlib.h. (cstdlib en C++)

Función Descripción
malloc asigna el número especificado de bytes
realloc aumenta o disminuye el tamaño del bloque de memoria especificada. Reasigna si es necesario
calloc asigna el número especificado de bytes y los inicializa a cero(0).
free libera el bloque de memoria especificada de nuevo al sistema

Las diferencias entre malloc() y calloc()

Hay dos diferencias entre estas funciones. En primer lugar, malloc() toma un único argumento (la cantidad de memoria para asignar en bytes), mientras calloc() necesita dos argumentos (el número de variables para asignar en la memoria y el tamaño en bytes de una sola variable).

En segundo lugar, malloc() no inicializa la memoria asignada, mientras calloc() inicializa todos los bytes del bloque de memoria asignada a cero.

Ejemplo de uso

Creación de un vector (array) de 10 enteros con el alcance automático es muy sencillo:

int array[10];

Sin embargo, el tamaño de la matriz se fija en tiempo de compilación. Si se quiere asignar una gama similar de forma dinámica, se puede utilizar el siguiente código:

/* Asignar espacio para una matriz con diez elementos de tipo int. Algunos programadores incluyen el conversor explícito  "(int *)" 

antes del malloc aunque no sea necesario. */
int * array = malloc(10 * sizeof(int));

/* Comprueba que la memoria se asignó correctamente, en caso contrario se gestiona el error. */
if (NULL == array) {
    /* gestión del error en la asignación… */
}

/* Si llegamos a este punto significa que la memoria ha sido asignada correctamente… */

/* Una vez hayamos finalizado el uso de la memoria debemos liberar la misma para usos futuros. */

free(array);

/* Nos aseguramos que el puntero ya no se usa asignándolo a NULL (u otra región de memoria asignada). */
array = NULL;

malloc() devuelve un puntero nulo (NULL) para indicar que no hay memoria disponible, o que se ha producido algún otro error que impidió la asignación de la memoria.

Tipo de seguridad

malloc devuelve un puntero nulo (void *), lo que indica que es un puntero a una región de tipo de datos desconocido. Se requiere el uso del casting en C + + debido al fuerte sistema de tipos, mientras que éste no es el caso de C. La falta de un tipo de puntero específico de retorno de malloc es un comportamiento de tipo-inseguro de acuerdo a algunos programadores: la asignación de memoria de malloc se basa en el recuento de bytes pero no en el tipo de dato. Esto es distinto a la asignación new de C++ que devuelve un puntero basado en el tipo de operando.

Uno puede usar un "cast" (ver conversión de tipos) de este puntero a un tipo específico:

int * ptr;
ptr = malloc (10 * sizeof (* ptr)); /* sin una conversión */
ptr = (int *) malloc (10 * sizeof(int)*ptr)); /* con un cast */
ptr = reinterpret_cast <int *> (malloc (10 * sizeof (* ptr))); /* con un cast, para C++ */

Hay ventajas y desventajas para la realización del cast.

Ventajas del cast

Desventajas del cast

Errores comunes

El uso inadecuado de asignación de memoria dinámica con frecuencia puede ser una fuente de errores.

La mayoría de los errores comunes son los siguientes:

Límite de tamaño

El mayor bloque de memoria que es posible reservar con malloc depende del sistema, en particular del tamaño de la memoria física y la implementación del sistema operativo. Teóricamente, este límite es el valor máximo que se puede mantener en un tipo size_t, que es un entero que depende del tamaño de un área de memoria asignado. El valor máximo es de 2CHAR_BIT × sizeof(size_t) − 1 o la constante SIZE_MAX en el estándar C99.

Enlaces externos

Inglés