Ir al contenido

Malloc

De Wikipedia, la enciclopedia libre
Esta es una versión antigua de esta página, editada a las 05:13 17 oct 2015 por 181.15.183.250 (discusión). La dirección URL es un enlace permanente a esta versión, que puede ser diferente de la versión actual.

Asignación dinámica de memoria C se refiere a la realización de la asignación de memoria dinámica en el Lenguaje de programación C a través de un grupo de funciones en la Biblioteca estándar de C , es decir, malloc , realloc , calloc y free .

El C + + lenguaje de programación incluye las siguientes funciones para la compatibilidad hacia atrás, y su uso en C + + ha sido sustituida en gran parte por los operadores new y new[].

Muchas implementaciones diferentes del mecanismo de asignación de memoria real, utilizado por malloc , están disponibles. 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 librería [[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 "cast" (ver conversión de tipos), este puntero a un tipo específico:

int * ptr;
ptr = malloc (10 * sizeof (* ptr)); / * sin una conversión * /
ptr = (int *) malloc (10 * sizeof (* 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

  • Incluyendo el cast permite un programa o función compilar como C++.
  • El cast permite versiones anteriores a 1989 de malloc que originalmente devuelven un char * .
  • cast puede ayudar al desarrollador a identificar incongruencias entre las llamadas y las asignaciones de datos, especialmente si el puntero se declara muy lejos de la llamada a malloc().

Desventajas del cast

  • Bajo el estándar ANSI C, el cast es redundante.
  • La adición de cast puede enmascarar la no inclusión de la cabecera stdlib.h , en el que el prototipo de malloc se encuentra. En ausencia de un prototipo para malloc, la norma requiere que el compilador de C asume malloc devuelve un int . Si no hay un cast, se emite un warning cuando se asigna este entero en el puntero, sin embargo, con el cast, esta advertencia no se produce, ocultando un error. En ciertas arquitecturas y modelos de datos (por ejemplo, LP64 en sistemas de 64 bits, en los que long y los punteros son de 64 bits y int es de 32 bits), este error de hecho puede dar lugar a un comportamiento indefinido, ya que el declarado implícitamente malloc devuelve un 32 - valor de bit, mientras que la función de realidad definida devuelve un valor de 64 bits. Dependiendo de convenciones de llamada y distribución de la memoria, esto puede dar lugar a aplastamiento pila. Este problema es menos probable que pase inadvertido en los compiladores modernos, ya que producen de manera uniforme las advertencias de que una función no declarada se ha utilizado, por lo que seguirá apareciendo una advertencia. Por ejemplo, el comportamiento por defecto para GCC es mostrar una advertencia que dice "declaración implícita incompatible de la función incorporada" con independencia de que el cast está presente o no.
  • Si el tipo del puntero se cambia, hay que arreglar todas las líneas de código donde malloc fue llamado y había echado (a menos que fue arrojado a un typedef ).

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:

  • No comprobar errores de asignación. La asignación de memoria no está garantizada que tenga éxito. Si no se comprueba la asignación de memoria, puede producirse un error del programa o de la totalidad del sistema.
  • Las pérdidas de memoria. Si no se desasignar memoria usando free conduce a la acumulación de la memoria de un solo uso, que ya no es utilizado por el programa. Estos recursos de memoria desperdiciados pueden conducir a errores de asignación cuando se hayan agotado esos recursos.
  • Los errores lógicos. Todas las asignaciones deben seguir el mismo patrón: la asignación mediante malloc , el uso para almacenar datos, desasignación mediante free . Las fallas que se adhieran a este patrón, como el uso de la memoria después de una llamada a la free o antes de una llamada a malloc , llamada a free dos veces seguidas ("doble liberación"), etc, por lo general conducen a una caída del programa.

Límites de tamaño Allocation

El mayor bloque de memoria posible malloc asignable depende del sistema, en particular del tamaño de la memoria física y la implementación del sistema operativo. Teóricamente, el número más grande debe ser 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.

Inglés