Universidad Carlos III de Madrid

Grado en Ing. Telemática/Sist. Audiovisuales/Sist. de Comunicaciones

Arquitectura de Sistemas

Septiembre 2012 - Enero 2013

5. Llamadas a las funciones de gestión de memoria

La primera observación cuando se ven los tipos de datos que manipulan las funciones de gestión de memoria es que el uso de memoria dinámica y el de punteros van de la mano. Un programa puede manipular una porción de memoria dinámica porque dispone de la dirección de su primer byte, y esta se almacena en un dato de tipo puntero. Este puntero se utiliza tanto para acceder a los datos que se almacenen en la memoria reservada, como para liberar ésta cuando no sea necesaria (con la función free()).

Cuando se llama a la función malloc el valor que retorna es una dirección de memoria de tipo void *, es decir, puntero a cualquier dato. Pero esa dirección de memoria se almacena en un programa en un puntero de un tipo diferente. Para evitar advertencias del compilador, se antepone a la llamada a malloc lo que se conoce como un casting. Un casting es una expresión escrita por el programador notificando al compilador de que una variable de un cierto tipo ahora debe ser considerada de otro tipo. Por ejemplo, la siguiente expresión reserva espacio para una estructura de tipo struct cell_info y la dirección de ese espacio se asigna al puntero cell_ptr.

#define TABLE_SIZE 10
struct cell_info
{
    int a;
    int b;
    int table[TABLE_SIZE];
};
struct cell_info *cell_ptr;

cell_ptr = (struct cell_info *)malloc(sizeof(struct cell_info));

Nótese que para saber el tamaño exacto de la porción de memoria a reservar se utiliza la función sizeof() que, dado cualquier tipo de datos o variable, devuelve el número de bytes que ocupa en memoria. El casting (struct cell_info *) hace que la asignación sobre la variable cell_ptr se haga como si la dirección de memoria fuese de este tipo, y por tanto es correcta.

Una vez obtenida la porción de memoria, el acceso se realiza normalmente utilizando el puntero obtenido, por ejemplo:

cell_ptr->a = 10;
cell_ptr->b = a + 20;
cell_ptr->table[5] = 0;

La regla general para invocar a la función malloc se puede enunciar de la siguiente forma. El espacio en memoria dinámica para una variable de tipo T se obtiene mediante

T *ptr = (T *)malloc(sizeof(T));

Una vez que una estructura de datos reservada con memoria dinámica no se necesita, se libera mediante la llamada a la función free. Siguiendo con el ejemplo anterior, se invoca con la línea

free(cell_ptr)

Responde a las siguientes preguntas para ver si has entendido lo que se explica en este documento:

  1. Las llamadas "malloc" y "calloc" en caso de que no se produzca error devuelven

    • Un puntero al inicio de la memoria reservada

    • Un puntero al final de la memoria reservada

    • Un puntero en medio de la memoria reservada

  2. Si p es un puntero a entero, y realizamos p=p+1;

    • El valor de p incrementa el tamaño de un entero

    • El valor de p incrementa el tamaño de un puntero