Asignación dinámica de memoria en C: Dominando malloc, calloc, realloc y free
Antes de sumergirte en la asignación dinámica de memoria en C, es esencial entender cómo se gestiona la memoria en el lenguaje.
Cómo funciona la gestión de memoria en C
Cuando declaras una variable con un tipo primitivo, el compilador asigna espacio para ella en la pila automáticamente. Por ejemplo, un float típicamente ocupa 4 bytes (dependiente de plataforma). Puedes confirmar esto con el operador sizeof:
#include <stdio.h> int main() { float x; printf("El tamaño de float es %d bytes", sizeof(x)); return 0; }
La salida será:
El tamaño de float es 4 bytes
Un array de tamaño especificado también se asigna contiguamente en la pila, con cada elemento ocupando el tamaño de su tipo:
#include <stdio.h> int main() { float arr[10]; printf("El tamaño del array float con 10 elementos es %d", sizeof(arr)); return 0; }
El resultado es:
El tamaño del array float con 10 elementos es 40
Mientras que la asignación en pila es automática, muchos programas requieren memoria cuyo tamaño no se conoce hasta tiempo de ejecución. Esta necesidad se aborda mediante asignación dinámica de memoria, que usa el montículo (heap) en lugar de la pila.
Asignación dinámica de memoria en C
La asignación dinámica implica solicitar y liberar memoria manualmente según se necesite, con punteros rastreando los bloques asignados en el montículo. La biblioteca estándar de C proporciona varias funciones para este propósito:
- malloc() – Asigna un bloque contiguo de bytes y retorna un puntero a su primer byte.
- calloc() – Asigna un array de elementos, inicializa todos los bytes a cero y retorna un puntero al primer elemento.
- realloc() – Redimensiona un bloque asignado previamente, preservando su contenido.
- free() – Libera un bloque asignado previamente de vuelta al montículo.
Exploremos cada función en detalle.
Función malloc()
La función malloc() significa "memory allocation". Reserva un bloque de memoria de un tamaño especificado y retorna un puntero a él. El puntero se castea típicamente al tipo deseado:
ptr = (tipo_cast *) malloc(tamaño_bytes);
Ejemplo:
#include <stdlib.h> int main(){ int *ptr; ptr = malloc(15 * sizeof(*ptr)); /* 15 enteros */ if (ptr != NULL) { *(ptr + 5) = 480; /* sexto elemento */ printf("Valor del 6to entero es %d", *(ptr + 5)); } }
Salida:
Valor del 6to entero es 480
Puntos clave:
- Usa
sizeof(*ptr)para hacer el código robusto contra cambios de tipo. - Verifica valor de retorno
NULLpara detectar fallo de asignación. - La memoria asignada es contigua; trátala como array y usa aritmética de punteros.
La asignación dinámica no se limita a tipos primitivos; funciona con estructuras, arrays de caracteres y más.
Función free()
La memoria asignada con malloc(), calloc() o realloc() debe liberarse explícitamente para evitar fugas. La función free() realiza esta tarea:
#include <stdio.h> int main() { int* ptr = malloc(10 * sizeof(*ptr)); if (ptr != NULL){ *(ptr + 2) = 50; printf("Valor del 2do entero es %d", *(ptr + 2)); } free(ptr); }
Salida:
Valor del 2do entero es 50
Función calloc()
calloc() asigna múltiples bloques de tamaño igual e inicializa cada byte a cero, lo que lo hace ideal para arrays y estructuras que requieren memoria puesta a cero:
ptr = (tipo_cast *) calloc(n, tamaño);
Ejemplo – sumar una secuencia aritmética:
#include <stdio.h> int main() { int i, *ptr, sum = 0; ptr = calloc(10, sizeof(int)); if (ptr == NULL) { printf("Error! memoria no asignada."); exit(0); } for (i = 0; i < 10; ++i) { *(ptr + i) = i; sum += *(ptr + i); } printf("Suma = %d", sum); free(ptr); return 0; }
Resultado:
Suma = 45
calloc() vs. malloc()
Diferencias clave:
- Inicialización:
calloc()pone memoria a cero;malloc()la deja sin inicializar (basura). - Uso:
calloc()es preferible para arrays o estructuras que necesitan valores a cero;malloc()es más simple cuando no se requiere inicialización. - Rendimiento: Ambos rinden similar, pero
calloc()puede ser ligeramente más lento por la puesta a cero.
Función realloc()
La función realloc() cambia el tamaño de una asignación existente preservando su contenido:
ptr = realloc(ptr, nuevo_tamaño);
Ejemplo – extender un búfer de cadena:
#include <stdio.h> int main () { char *ptr = malloc(10); strcpy(ptr, "Programación"); ptr = realloc(ptr, 20); // agrandar strcat(ptr, " En 'C'"); printf("%s, Dirección = %u", ptr, ptr); free(ptr); return 0; }
Si la reasignación falla, realloc() retorna NULL y el bloque original permanece válido.
Arrays dinámicos
Los arrays dinámicos permiten que el número de elementos crezca durante la ejecución, un patrón común en algoritmos y estructuras de datos:
#include <stdio.h> int main() { int *arr_dynamic = NULL; int elementos = 2, i; arr_dynamic = calloc(elementos, sizeof(int)); for (i = 0; i < elementos; i++) arr_dynamic[i] = i; for (i = 0; i < elementos; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]); elementos = 4; arr_dynamic = realloc(arr_dynamic, elementos * sizeof(int)); printf("Después de realloc\n"); for (i = 2; i < elementos; i++) arr_dynamic[i] = i; for (i = 0; i < elementos; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]); free(arr_dynamic); }
Resultado:
arr_dynamic[0]=0 arr_dynamic[1]=1 Después de realloc arr_dynamic[0]=0 arr_dynamic[1]=1 arr_dynamic[2]=2 arr_dynamic[3]=3
Resumen
- La memoria dinámica permite asignar y desasignar espacio en el montículo en tiempo de ejecución.
- Usa
malloc()para bloques únicos,calloc()para arrays inicializados a cero. - Siempre verifica
NULLpara detectar fallos de asignación. - Libera memoria con
free()para evitar fugas. - Redimensiona asignaciones con
realloc()cuando se necesite más espacio. - Los arrays dinámicos son un patrón potente para estructuras de datos flexibles.
Lenguaje C
- Entendiendo ROM, PROM, EPROM y EEPROM: Diseño, Programación e Identificación
- Fundamentos de C#: Entrada y salida esenciales
- Dominando las Sentencias Using en C#: Importaciones, Alias y Directivas Estáticas
- Dominando la gestión de memoria en C++: uso experto de new y delete
- Cuatro patrones probados para funciones definidas por el usuario en C
- Asignación dinámica de memoria en C: Dominando malloc, calloc, realloc y free
- Dominando funciones de la biblioteca estándar de C: Guía práctica
- Asignación dinámica de arrays en C++: Guía práctica con ejemplos de código
- Funciones en C++ Explicadas con Ejemplos de Código Prácticos
- Dominando funciones en C: Estructura, declaración y mejores prácticas
- Gestión Dinámica de Memoria en C: calloc, malloc y free Explicados