Fundamentos de Tipos Enumerados y Gestión Dinámica de Memoria en C
Clasificado en Informática
Escrito el en español con un tamaño de 6,01 KB
Tipos de Dato Enumerados (`enum`) en C
Los tipos de dato enumerados, o enum
, son el modo más simple de crear un nuevo tipo de dato definido por el usuario en C. Cuando definimos un tipo de dato enumerado, lo que hacemos es especificar explícitamente cada uno de los valores que conformarán su dominio; es decir, se trata de una definición por extensión.
La sintaxis para la creación de un nuevo tipo de dato enumerado es la siguiente:
enum identificador {id_1[, id_2, ..., id_N]};
Donde identificador
es el nombre que recibirá el nuevo tipo de dato. Los elementos id_1
, id_2
, etc., son los diferentes identificadores de cada uno de los valores que componen el nuevo dominio de este tipo de dato.
Nota: enum
es una de las 32 palabras reservadas del lenguaje C.
Mediante enum
se pueden crear tipos de dato que son subconjuntos de los tipos de dato int
. De hecho, las variables declaradas de tipo enum
son tratadas como si fuesen de tipo int
.
Por defecto, el primer símbolo o literal de enumeración se inicializa a cero, el segundo a uno, y así sucesivamente, a menos que se especifique una inicialización diferente.
Asignación Dinámica de Memoria en C
En numerosas ocasiones, la cantidad de memoria necesaria para un programa no se conoce hasta el momento de su ejecución. El método para resolver este inconveniente es recurrir al uso de punteros y a técnicas de asignación dinámica de memoria.
El espacio de memoria para las variables asignadas dinámicamente se crea durante la ejecución del programa, a diferencia de las variables estáticas o automáticas cuyo tamaño se define en tiempo de compilación.
Funciones Esenciales para la Gestión Dinámica de Memoria
En C, las funciones malloc()
, realloc()
, calloc()
y free()
son fundamentales para asignar y liberar memoria de un bloque de memoria conocido como montículo o heap del sistema.
Estas funciones permiten la gestión dinámica de la memoria, lo que significa que pueden asignar y liberar espacio de memoria durante la ejecución de un programa, adaptándose a las necesidades cambiantes de almacenamiento.
Función malloc()
La función malloc()
reserva un bloque de memoria cuyo tamaño, en bytes, es el número pasado como argumento. malloc()
devuelve un puntero, que es la dirección del primer byte del bloque de memoria asignado. Este puntero se utiliza para referenciar el bloque de memoria.
El puntero que devuelve es de tipo void*
, lo que significa que puede ser asignado a cualquier tipo de puntero sin necesidad de una conversión explícita en C (aunque es buena práctica y necesaria en C++).
La sintaxis para llamar a la función es:
puntero = malloc(tamaño_en_bytes);
Generalmente, se realiza una conversión explícita al tipo de puntero deseado para mayor claridad y compatibilidad:
tipo *puntero;puntero = (tipo*)malloc(tamaño_en_bytes);
Función free()
Cuando un bloque de memoria previamente asignado por malloc()
, calloc()
, realloc()
o cualquier otra función de asignación ya no es necesario, se puede liberar el espacio de memoria y dejarlo disponible para otros usos mediante una llamada a la función free()
.
El bloque de memoria liberado se devuelve al espacio de almacenamiento libre (el heap), lo que permite que esa memoria pueda ser reasignada para otros propósitos.
Su prototipo es:
void free(void* ptr);
Donde ptr
es el puntero al bloque de memoria que se desea liberar.
Función calloc()
La función calloc()
asigna la memoria solicitada y devuelve un puntero a la misma. La principal diferencia entre malloc()
y calloc()
es que malloc()
no inicializa el contenido de la memoria asignada, mientras que calloc()
sí lo hace, estableciendo todos los bits a cero.
El prototipo de calloc()
es:
void* calloc(size_t num_elementos, size_t tam_elemento);
Donde num_elementos
es el número de elementos a asignar y tam_elemento
es el tamaño en bytes de cada elemento. La memoria total asignada será num_elementos * tam_elemento
.
Función realloc()
La función realloc()
se utiliza para cambiar el tamaño de un bloque de memoria previamente asignado. Puede ampliarlo o reducirlo.
Su prototipo es:
void* realloc(void* puntero_a_bloque, size_t nuevo_tamano);
El primer argumento, puntero_a_bloque
, debe ser un puntero a un bloque de memoria previamente asignado con malloc()
, calloc()
o la propia realloc()
.
El segundo argumento, nuevo_tamano
, es el nuevo tamaño total, en bytes, que se desea para el bloque de memoria. Si realloc()
no puede expandir el bloque en su ubicación actual, intentará encontrar un nuevo bloque de memoria de ese tamaño, copiará el contenido del bloque original al nuevo y liberará el original. Si no puede asignar el nuevo bloque, devuelve NULL
.
Estructuras Dinámicas de Datos
Las estructuras dinámicas de datos están compuestas por elementos más pequeños, comúnmente llamados nodos, que agrupan los datos con los que trabajará el programa. Además, estos nodos suelen contener uno o más punteros autorreferenciables, es decir, punteros a objetos del mismo tipo de nodo, lo que permite encadenarlos y formar estructuras complejas como listas enlazadas, árboles o grafos.