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: