Acerca de¶
A diferencia de la memoria estática (stack), la memoria dinámica (heap) nos
permite solicitar y liberar bloques de memoria en tiempo de ejecución en C11, cuyo
tamaño puede no ser conocido al momento de compilar. Estos ejercicios se centran
en el uso correcto de malloc, calloc, realloc y free para gestionar el
ciclo de vida de arreglos, cadenas y matrices.
Capítulos de Apunte Correspondientes¶
Prerrequisitos Conceptuales¶
Antes de resolver esta guía, el estudiante debe dominar:
Memoria Heap frente a memoria Stack: ciclo de vida manual vs automático (Memoria dinámica: propiedad y ciclo de vida).
Funciones de asignación (
malloc,calloc,realloc) y verificación de puntero nulo (NULL).Liberación simétrica y completa con
freey anulación de puntero (dangling pointer prevention).Detección de fugas de memoria (memory leaks) y accesos inválidos (use-after-free).
Cuestiones de Estilo Aplicables¶
Verificación de Retorno: Siempre se debe comprobar que el retorno de
mallocoreallocsea distinto deNULLantes de desreferenciarlo (0x3001h: Siempre verificá la asignación exitosa de memoria dinámica).Liberación Segura: Tras liberar un bloque con
free(ptr), asignáptr = NULLpara mitigar referencias colgantes (0x3002h: Liberá siempre la memoria dinámica y asigná NULL al puntero para mitigar punteros colgantes).
Arreglos Dinámicos¶
Ejercicio 2.05.01 - Ciclo de Vida de Arreglo Dinámico ⭐⭐☆☆☆¶
(ej_b2_c05_02)=
### Ejercicio 2.05.02 - Duplicación de Arreglo en Heap ⭐⭐☆☆☆
:::{exercise}
:label: ej_b2_c05_02_duplicar
Implementá una función que cree una copia exacta e independiente en memoria dinámica
de un arreglo recibido.
```c
int *duplicar_arreglo_dinamico(const int *origen, size_t n);
```
**Tabla de Vectores de Prueba:**
| Arreglo Origen | `n` | Copia Retornada | Comportamiento |
| :--- | :--- | :--- | :--- |
| `[10, 20, 30]` | `3` | Puntero a nuevo bloque con `[10, 20, 30]` | Memoria independiente |
| `NULL` o vacío | `0` | `NULL` | Retorno seguro |
::::{solution}
```c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int *duplicar_arreglo_dinamico(const int *origen, size_t n) {
if (origen == NULL || n == 0) {
return NULL;
}
int *copia = (int *)malloc(n * sizeof(int));
if (copia == NULL) {
return NULL;
}
for (size_t i = 0; i < n; ++i) {
copia[i] = origen[i];
}
return copia;
}
int main(void) {
int orig[] = {10, 20, 30};
int *clon = duplicar_arreglo_dinamico(orig, 3);
assert(clon != NULL);
assert(clon != orig);
for (size_t i = 0; i < 3; ++i) {
assert(clon[i] == orig[i]);
}
clon[0] = 999;
assert(orig[0] == 10); /* Verificación de independencia */
free(clon);
assert(duplicar_arreglo_dinamico(NULL, 5) == NULL);
return 0;
}
```
(ej_b2_c05_03)=
### Ejercicio 2.05.03 - Fusión de Arreglos Ordenados en Heap ⭐⭐⭐☆☆
:::{exercise}
:label: ej_b2_c05_03_fusion
Implementá una función que tome dos arreglos ordenados ascendentemente y retorne
un nuevo bloque dinámico conteniendo todos los elementos fusionados en orden.
```c
int *fusionar_arreglos_ordenados(const int *a1, size_t n1, const int *a2, size_t n2);
```
**Tabla de Vectores de Prueba:**
| Arreglo 1 | Arreglo 2 | Resultado Fusionado |
| :--- | :--- | :--- |
| `[1, 5, 9]` | `[2, 4, 8, 10]` | `[1, 2, 4, 5, 8, 9, 10]` |
| `[10, 20]` | `[]` | `[10, 20]` |
| `[]` | `[3, 7]` | `[3, 7]` |
::::{solution}
```c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int *fusionar_arreglos_ordenados(const int *a1, size_t n1, const int *a2, size_t n2) {
size_t total = n1 + n2;
if (total == 0) {
return NULL;
}
int *res = (int *)malloc(total * sizeof(int));
if (res == NULL) {
return NULL;
}
size_t i = 0;
size_t j = 0;
size_t k = 0;
while (i < n1 && j < n2) {
if (a1[i] <= a2[j]) {
res[k++] = a1[i++];
} else {
res[k++] = a2[j++];
}
}
while (i < n1) {
res[k++] = a1[i++];
}
while (j < n2) {
res[k++] = a2[j++];
}
return res;
}
int main(void) {
int a1[] = {1, 5, 9};
int a2[] = {2, 4, 8, 10};
int *fus = fusionar_arreglos_ordenados(a1, 3, a2, 4);
assert(fus != NULL);
int esp[] = {1, 2, 4, 5, 8, 9, 10};
for (size_t idx = 0; idx < 7; ++idx) {
assert(fus[idx] == esp[idx]);
}
free(fus);
int *fus2 = fusionar_arreglos_ordenados(a1, 3, NULL, 0);
assert(fus2 != NULL && fus2[0] == 1 && fus2[1] == 5 && fus2[2] == 9);
free(fus2);
return 0;
}
```
(ej_b2_c05_04)=
### Ejercicio 2.05.04 - Inserción Dinámica Defensiva con Realloc ⭐⭐⭐☆☆
:::{exercise}
:label: ej_b2_c05_04_insercion_dinamica
:enumerator: memoria-dinamica-4
Implementá una función defensiva que inserte un nuevo elemento en cualquier posición de un arreglo en el heap, redimensionándolo dinámicamente:
```c
bool arreglo_dinamico_insertar(int **arr, size_t *tam, size_t pos, int valor);
```
Debés:
1. Validar que los punteros sean válidos y que `pos <= *tam`.
2. Asignar un nuevo búfer con `realloc` utilizando una variable temporal para no perder la referencia previa en caso de fallo.
3. Desplazar los elementos existentes desde `pos` hacia la derecha utilizando `memmove` (evitando solapamientos no definidos).
4. Escribir `valor` en la posición `pos` e incrementar `*tam`.
**Nivel de Bloom:** Nivel 4 (Análisis).
**Conceptos requeridos:** Puntero doble `int **`, realocación defensiva sin fugas de memoria, `memmove` para regiones superpuestas.
**Techo conceptual:** Prohibido reasignar directamente el puntero original con `*arr = realloc(*arr, ...)` sin validar el retorno.
#### Contrato de la Función
- **Firma:** `bool arreglo_dinamico_insertar(int **arr, size_t *tam, size_t pos, int valor);`
- **Precondiciones:** `arr != NULL`, `tam != NULL`, `pos <= *tam`.
- **Postcondiciones:** Retorna `true` y actualiza el arreglo; si falla la asignación o los parámetros son inválidos retorna `false` y preserva la memoria original intacta.
#### Tabla de Vectores de Prueba
| Estado Inicial | Posición / Valor | Retorno | Arreglo Resultante | Justificación Técnica |
| :--- | :--- | :--- | :--- | :--- |
| `[10, 30]`, tam=2 | `pos=1, val=20` | `true` | `[10, 20, 30]`, tam=3 | Inserción en posición intermedia |
| `[10, 20]`, tam=2 | `pos=0, val=5` | `true` | `[5, 10, 20]`, tam=3 | Inserción al inicio con desplazamiento completo |
| `[10, 20]`, tam=2 | `pos=2, val=99` | `true` | `[10, 20, 99]`, tam=3 | Inserción al final sin desplazamiento |
| `NULL`, tam=0 | `pos=0, val=42` | `true` | `[42]`, tam=1 | Inserción inicial en arreglo vacío |
| `[10]`, tam=1 | `pos=5, val=100` | `false` | `[10]`, tam=1 | Rechazo seguro de posición fuera de rango |
Solution to ej_b2_c05_04_insercion_dinamica
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62#include <assert.h> #include <stdbool.h> #include <stddef.h> #include <stdlib.h> #include <string.h> bool arreglo_dinamico_insertar(int **arr, size_t *tam, size_t pos, int valor) { if (arr == NULL || tam == NULL || pos > *tam) { return false; } size_t nuevo_tam = *tam + 1; int *nuevo_bloque = (int *)realloc(*arr, nuevo_tam * sizeof(int)); if (nuevo_bloque == NULL) { return false; } *arr = nuevo_bloque; // Desplazar elementos desde 'pos' hacia la derecha si no se inserta al final if (pos < *tam) { size_t elementos_a_mover = *tam - pos; memmove(&(*arr)[pos + 1], &(*arr)[pos], elementos_a_mover * sizeof(int)); } (*arr)[pos] = valor; *tam = nuevo_tam; return true; } int main(void) { int *arr = NULL; size_t tam = 0; // Inserción en vacío assert(arreglo_dinamico_insertar(&arr, &tam, 0, 10) == true); assert(tam == 1 && arr[0] == 10); // Inserción al final assert(arreglo_dinamico_insertar(&arr, &tam, 1, 30) == true); assert(tam == 2 && arr[0] == 10 && arr[1] == 30); // Inserción en el medio assert(arreglo_dinamico_insertar(&arr, &tam, 1, 20) == true); assert(tam == 3 && arr[0] == 10 && arr[1] == 20 && arr[2] == 30); // Inserción al inicio assert(arreglo_dinamico_insertar(&arr, &tam, 0, 5) == true); assert(tam == 4 && arr[0] == 5 && arr[1] == 10 && arr[2] == 20 && arr[3] == 30); // Caso inválido: posición fuera de rango assert(arreglo_dinamico_insertar(&arr, &tam, 99, 100) == false); assert(tam == 4); free(arr); return 0; }
Cadenas Dinámicas¶
Ejercicio 2.05.05 - Concatenación dinámica ⭐⭐⭐☆☆¶
Implementar char* concatenar(const char *s1, const char *s2). Algoritmo:
Calcular la longitud total necesaria:
strlen(s1) + strlen(s2) + 1(para el\0).Reservar memoria con
mallocpara este tamaño.Copiar la primera cadena (
s1) al nuevo bloque.Concatenar la segunda cadena (
s2) al final.
Ejercicio 2.05.06 - Deduplicador ⭐⭐☆☆☆¶
Implementar char* deduplicar(const char *s). Como el tamaño final es
desconocido, una estrategia de dos pasadas es robusta:
Primera pasada: Recorrer la cadena
scon un arreglo auxiliar de contadores para determinar el número de caracteres únicos y, por lo tanto, el tamaño de la cadena resultante.Segunda pasada: Reservar memoria del tamaño exacto y construir la nueva cadena solo con los caracteres únicos.
Ejercicio 2.05.07 - Fraccionador (Tokenizer) ⭐⭐☆☆☆¶
Implementar char** dividir_cadena(const char *s, int *n_palabras). Esta
función devuelve un arreglo de punteros, donde cada puntero apunta a una palabra
alojada dinámicamente.
Algoritmo:
Contar el número de palabras para saber el tamaño del arreglo
char**.Reservar memoria para este arreglo de punteros.
Volver a recorrer la cadena original. Por cada palabra encontrada: a. Calcular su longitud. b. Reservar memoria para esa palabra. c. Copiar los caracteres de la palabra. d. Asignar el puntero a la nueva palabra en el arreglo de punteros.
Terminar el arreglo de punteros con un
NULLpara facilitar su recorrido.
Matrices Dinámicas¶
Ejercicio 2.05.08 - Ciclo de vida ⭐⭐☆☆☆¶
Implementar funciones para reservar y liberar una matriz m x n usando un
arreglo de punteros.
Reserva: Se realiza en dos etapas. Primero se reserva el arreglo de punteros a las filas, y luego, en un lazo, se reserva la memoria para cada fila individual.
Liberación: Debe seguir el orden inverso. Primero, en un lazo, se libera la memoria de cada fila, y finalmente se libera el arreglo que contenía los punteros a las filas.
Ejercicio 2.05.09 - Multiplicación ⭐⭐☆☆☆¶
Implementar int** multiplicar(int **A, int m, int n, int **B, int p, int q).
Algoritmo:
Verificar que la multiplicación sea posible ( debe ser igual a ).
Reservar memoria para una nueva matriz
Cde dimensiones .Aplicar el algoritmo de multiplicación de matrices para calcular cada elemento y almacenarlo en la nueva matriz.
Retornar el puntero a la matriz
C.
Ejercicio 2.05.10 - s Adicionales ⭐⭐☆☆☆¶
Ejercicio 2.05.11 - Redimensionar Arreglo ⭐⭐⭐☆☆¶
Implementar una función int* redimensionar_arreglo(int* arr, size_t nuevo_tamano) que utilice realloc para cambiar el tamaño de un arreglo
dinámico. La función debe manejar tanto la expansión como la contracción del
arreglo y gestionar posibles fallos de realloc.
Ejercicio 2.05.12 - Vector de Crecimiento Dinámico ⭐⭐⭐☆☆¶
Implementar una estructura vector_t que simule un std::vector de C++. Debe
contener un puntero a los datos, un tamaño (size) y una capacidad
(capacity). Crear funciones para:
vector_crear(): Inicializa un vector vacío.vector_push_back(vector_t* v, int dato): Añade un elemento al final. Sisize == capacity, debe duplicar la capacidad usandorealloc.vector_destruir(vector_t* v): Libera toda la memoria.
Ejercicio 2.05.13 - Leer Archivo a Cadena Dinámica ⭐⭐⭐☆☆¶
Escribir una función char* leer_archivo_completo(const char* ruta) que lea
todo el contenido de un archivo de texto y lo devuelva en una única cadena
alojada dinámicamente. El tamaño del archivo no se conoce de antemano.
Ejercicio 2.05.14 - Matriz Triangular Dinámica ⭐⭐⭐☆☆¶
Crear una función que reserve memoria para una matriz triangular inferior. Cada
fila i debe tener i+1 columnas. La función debe devolver un int** y se
debe implementar su correspondiente función de liberación.
Ejercicio 2.05.15 - strdup Propio ⭐⭐☆☆☆¶
Implementar su propia versión de la función no estándar strdup, que recibe una
cadena y devuelve un puntero a una nueva cadena en memoria dinámica con el mismo
contenido.
char* mi_strdup(const char* s);
Ejercicio 2.05.16 - calloc vs. malloc ⭐⭐☆☆☆¶
Escribir un programa que reserve dos arreglos de enteros del mismo tamaño, uno
con malloc y otro con calloc. Imprimir el contenido de ambos arreglos
inmediatamente después de la reserva para demostrar que calloc inicializa la
memoria a cero.
Ejercicio 2.05.17 - Concatenar Múltiples Cadenas ⭐⭐⭐☆☆¶
Escribir una función char* concatenar_muchas(char** cadenas, int n_cadenas)
que reciba un arreglo de cadenas y las una todas en una sola cadena dinámica,
separadas por un espacio.
Ejercicio 2.05.18 - Clonación Profunda de Struct ⭐⭐⭐☆☆¶
Definir una struct que contenga miembros de tipo puntero (ej. char* nombre,
int* notas). Escribir una función de “clonación profunda” que cree una copia
completamente nueva e independiente de la struct, incluyendo la reserva de
nueva memoria para los datos a los que apuntan los punteros.
Ejercicio 2.05.19 - Particionar Arreglo Dinámicamente ⭐⭐⭐☆☆¶
Escribir una función que reciba un arreglo dinámico y lo divida en dos nuevos arreglos dinámicos: uno con los números pares y otro con los impares. La función debe devolver estos dos nuevos arreglos (por ejemplo, a través de punteros por referencia).
Ejercicio 2.05.20 - Historial de Comandos ⭐⭐☆☆☆¶
Crear un programa que lea líneas de texto desde la entrada estándar y las
almacene en un “historial” (un arreglo dinámico de cadenas char**). El
historial debe crecer dinámicamente a medida que se añaden comandos.
Ejercicio 2.05.21 - Matriz Irregular (Ragged Array) ⭐⭐⭐☆☆¶
Reservar memoria para una matriz dinámica donde cada fila puede tener un número diferente de columnas. Las dimensiones (número de columnas de cada fila) se deben leer de un arreglo de configuración.
Ejercicio 2.05.22 - Liberación Profunda ⭐⭐☆☆☆¶
Escribir una función void liberar_historial(char** historial, int n_comandos)
que libere correctamente toda la memoria utilizada por la estructura del
ejercicio 1.19: primero la memoria de cada cadena individual y luego la memoria
del arreglo de punteros.
Ejercicio 2.05.23 - Buffer de Lectura Dinámico ⭐⭐⭐☆☆¶
Crear una función que lea una línea completa desde stdin (hasta el salto de
línea), alojando dinámicamente la memoria necesaria para la línea sin imponer un
límite de tamaño predefinido. La función podría empezar con un buffer pequeño y
usar realloc para agrandarlo según sea necesario.
Ejercicio 2.05.24 - Lista de Compras Dinámica ⭐⭐⭐☆☆¶
Crear un programa interactivo que permita al usuario gestionar una lista de compras. Las opciones deben ser:
Añadir producto (cadena dinámica).
Eliminar producto.
Mostrar lista. La lista debe ser un arreglo de
char*que se ajuste dinámicamente.
Ejercicio 2.05.25 - Manejo de Errores de malloc ⭐⭐☆☆☆¶
Modificar uno de los ejercicios anteriores (ej. 1.2, Duplicadora) para que, si
malloc o realloc devuelven NULL, el programa lo notifique con un mensaje
de error claro a stderr y termine de forma controlada (ej.
exit(EXIT_FAILURE)), en lugar de fallar por desreferenciar un puntero nulo.
Más Ejercicios de Memoria Dinámica¶
Ejercicio 2.05.26 - Filtro de Arreglo Dinámico ⭐⭐⭐☆☆¶
Crear una función que reciba un arreglo dinámico, su tamaño y un puntero a una
función “predicado” (bool (*pred)(int)). La función debe devolver un nuevo
arreglo dinámico que contenga únicamente los elementos del arreglo original para
los cuales el predicado devuelve true.
Ejercicio 2.05.27 - Mapa Simple (Clave-Valor) ⭐☆☆☆☆¶
Implementar una estructura para un mapa simple (diccionario) que almacene pares
clave-valor (char*-int). El mapa debe usar un arreglo dinámico de struct par {char* clave; int valor;}. La tabla debe crecer usando realloc cuando se
quede sin espacio.
Ejercicio 2.05.28 - Unir Líneas de Archivo ⭐⭐☆☆☆¶
Escribir un programa que lea todas las líneas de un archivo y las almacene en un
arreglo dinámico de cadenas (char**). Luego, crear una función que una todas
estas cadenas en una sola, separadas por un espacio, y la devuelva como una
nueva cadena dinámica.
Ejercicio 2.05.29 - Sub-arreglo Dinámico ⭐⭐⭐☆☆¶
Crear una función int* sub_arreglo(const int* arr, size_t inicio, size_t fin)
que devuelva un nuevo arreglo dinámico conteniendo una copia de los elementos
del arreglo original desde el índice inicio hasta fin-1.
Ejercicio 2.05.30 - Matriz Dinámica en Bloque Contiguo ⭐⭐⭐☆☆¶
Implementar la creación y liberación de una matriz M x N de dos formas:
Como un arreglo de punteros a filas (el método tradicional).
Como un único bloque de memoria contigua de
M*Nelementos, y un arreglo de punterosint**donde cada puntero[i]se calcula para que apunte a la filaidentro del bloque contiguo. Comparar la complejidad de liberación de ambas.
Ejercicio 2.05.31 - realloc con NULL ⭐⭐☆☆☆¶
Escribir un pequeño programa que demuestre que realloc(NULL, n) se comporta de
manera idéntica a malloc(n). Verificar que la memoria se asigna correctamente.
Ejercicio 2.05.32 - realloc con Tamaño Cero ⭐⭐☆☆☆¶
Escribir un pequeño programa que demuestre que realloc(ptr, 0) se comporta de
manera idéntica a free(ptr). Verificar que el puntero original ya no es válido
después de la operación.
Ejercicio 2.05.33 - Arreglo Dinámico de Structs ⭐⭐⭐☆☆¶
Alojar dinámicamente un arreglo de structs (ej. producto_t de un ejercicio
anterior). Implementar funciones para añadir y buscar elementos en este arreglo,
usando realloc para expandir el arreglo cuando sea necesario.
Ejercicio 2.05.34 - Implementar getline ⭐⭐☆☆☆¶
Implementar una versión simplificada de la función getline de POSIX. La
función ssize_t mi_getline(char **lineptr, size_t *n, FILE *stream) debe leer
una línea de stream, almacenarla en un buffer apuntado por *lineptr y
expandir dicho buffer con realloc si es necesario.
Ejercicio 2.05.35 - Pila (Stack) Dinámica ⭐⭐⭐☆☆¶
Implementar una Pila (Stack) usando un arreglo dinámico. La estructura debe
tener capacidad y tamaño. Cuando la pila se llena, su capacidad debe duplicarse.
Cuando el tamaño es un cuarto de la capacidad, esta debe reducirse a la mitad.
Implementar push, pop y peek.
Ejercicio 2.05.36 - Array Dinámico Simple ⭐☆☆☆☆¶
Leé un tamaño n, creá un array dinámico de n enteros, llenalo, mostralo y
liberalo.
Orientación:
int *arr = malloc(n * sizeof(int));Verificá:
if (arr == NULL) return 1;Al final:
free(arr);
Ejercicio 2.05.37 - String Dinámico ⭐⭐☆☆☆¶
Leé un string de tamaño arbitrario (hasta 1000 caracteres), almacenalo dinámicamente con el tamaño exacto.
Orientación:
Leé en buffer temporal:
char temp[1001];Asigná memoria exacta:
strlen(temp) + 1Copiá con
strcpyLiberá al final
Ejercicio 2.05.38 - Redimensionar Array ⭐⭐⭐☆☆¶
Implementá un programa que permita agregar elementos dinámicamente a un array, redimensionándolo cuando se llene.
Orientación:
Mantené
capacidadactual ytamaniousadoCuando
tamanio == capacidad, duplicá capacidad conreallocarr = realloc(arr, nueva_capacidad * sizeof(int));Verificá que
reallocno retorne NULL
Ejercicio 2.05.39 - Copiar String Dinámicamente ⭐⭐⭐☆☆¶
Implementá char *duplicar_string(const char *src) que retorne una copia
dinámica.
Orientación:
Calculá longitud con
strlenAsigná
strlen + 1bytes (para ‘\0’)Copiá con
strcpyEl llamador es responsable de liberar
Ejercicio 2.05.40 - Concatenar Strings Dinámicamente ⭐⭐⭐☆☆¶
Implementá char *concatenar(const char *s1, const char *s2) que retorne
concatenación en memoria dinámica.
Orientación:
Longitud total =
strlen(s1) + strlen(s2) + 1Copiá s1 primero, luego s2
Retorná el nuevo string
Ejercicio 2.05.41 - Matriz Dentada ⭐⭐⭐⭐☆¶
Creá una matriz donde cada fila tiene diferente cantidad de columnas.
Orientación:
int **matriz = malloc(filas * sizeof(int*));Para cada fila:
matriz[i] = malloc(cols[i] * sizeof(int));Liberá en orden inverso: filas primero, luego array de punteros
Ejercicio 2.05.42 - Lista de Strings ⭐⭐⭐⭐☆¶
Leé N strings y almacenalos en un array dinámico de strings.
Orientación:
char **strings = malloc(n * sizeof(char*));Para cada string: asigná memoria exacta
Liberá cada string individualmente, luego el array
Ejercicio 2.05.43 - Histograma Dinámico ⭐⭐⭐⭐☆¶
Leé números hasta EOF y creá un histograma de frecuencias (0-9).
Orientación:
Asigná array dinámico de 10 enteros (inicializado a 0)
Usá
calloc(10, sizeof(int))para inicialización automáticaIncrementá contador según el dígito
Mostrá histograma visual con asteriscos
Ejercicio 2.05.44 - Vector Dinámico (Estructura) ⭐⭐⭐⭐☆¶
Implementá un vector dinámico encapsulado en estructura:
typedef struct
{
int *datos;
size_t tamanio;
size_t capacidad;
} vector_t;Funciones:
vector_t *crear_vector()void agregar(vector_t *v, int valor)void destruir_vector(vector_t *v)
Orientación:
crear_vectorasigna estructura y array inicialagregarredimensiona si es necesariodestruir_vectorlibera datos y luego estructura
Ejercicio 2.05.45 - Leer Archivo Completo en Memoria ⭐⭐⭐⭐☆¶
Leé un archivo de texto completo en memoria dinámica.
Orientación:
Obtené tamaño con
fseekyftellAsigná
tamanio + 1bytesLeé todo con
freadTerminá con ‘\0’
Liberá memoria al terminar
Ejercicio 2.05.46 - Merge de Arrays ⭐⭐⭐⭐☆¶
Implementá int *merge(int *arr1, int n1, int *arr2, int n2) que retorne un
nuevo array con ambos ordenados.
Orientación:
Asigná array de tamaño
n1 + n2Usá dos índices para recorrer ambos arrays
Copiá el menor en cada paso
Liberá los arrays originales si ya no se usan
Ejercicio 2.05.47 - Lista Enlazada con Memoria Dinámica ⭐⭐⭐⭐⭐¶
Implementá lista enlazada completamente dinámica:
typedef struct nodo
{
int dato;
struct nodo *siguiente;
} nodo_t;Funciones:
nodo_t *crear_nodo(int valor)void insertar_ordenado(nodo_t **cabeza, int valor)void eliminar_valor(nodo_t **cabeza, int valor)void liberar_lista(nodo_t **cabeza)
Orientación:
Cada nodo se asigna con
mallocinsertar_ordenadoencuentra posición correctaeliminar_valorbusca, reenlaza y liberaliberar_listarecorre y libera todos los nodos
Ejercicio 2.05.48 - Árbol Binario de Búsqueda ⭐⭐⭐⭐⭐¶
Implementá un ABB (Árbol Binario de Búsqueda):
typedef struct nodo_arbol
{
int dato;
struct nodo_arbol *izquierdo;
struct nodo_arbol *derecho;
} nodo_arbol_t;Funciones:
nodo_arbol_t *insertar(nodo_arbol_t *raiz, int valor)bool buscar(nodo_arbol_t *raiz, int valor)void liberar_arbol(nodo_arbol_t *raiz)
Orientación:
Inserción recursiva: menor a izquierda, mayor a derecha
Búsqueda recursiva similar
Liberación: postorden (izquierdo, derecho, raíz)
Ejercicio 2.05.49 - Tabla Hash Simple ⭐⭐⭐⭐⭐¶
Implementá una tabla hash con encadenamiento:
1 2 3 4 5 6 7 8 9 10 11typedef struct entrada { char *clave; int valor; struct entrada *siguiente; } entrada_t; typedef struct { entrada_t **tabla; size_t tamanio; } hash_t;
Funciones:
hash_t *crear_hash(size_t tam)void insertar(hash_t *h, const char *clave, int valor)int *buscar(hash_t *h, const char *clave)void destruir_hash(hash_t *h)
Orientación:
Función hash simple: suma de caracteres % tamaño
Encadenamiento para colisiones
Destruir: libera cadenas, claves, y tabla
Ejercicio 2.05.50 - Pool de Memoria ⭐⭐⭐⭐⭐¶
Implementá un allocator simple que asigna de un pool preasignado.
Orientación:
Asigná bloque grande inicial con
mallocMantené puntero a espacio libre
pool_alloc(size)retorna puntero y avanzapool_free()libera todo el pool de una vezNo soporta liberación individual
Ejercicio 2.05.51 - Parser de CSV Dinámico ⭐⭐⭐⭐⭐¶
Leé un archivo CSV y almacená datos en estructura dinámica.
Orientación:
Leé línea por línea con
fgetsParseá con
strtoko manualmenteAlmacená en array dinámico de estructuras
Redimensioná si es necesario
Liberá todo al terminar
Ejercicio 2.05.52 - Búfer Circular Dinámico ⭐⭐⭐⭐⭐¶
Implementá un búfer circular continuo en memoria dinámica:
Orientación:
Asigná un arreglo continuo dinámico de enteros con
mallocMantené los índices
inicio,finy la cantidad de elementosSi el búfer se llena, duplicá su capacidad reubicando los elementos en orden contiguo
Liberá toda la memoria al destruir el búfer
Ejercicio 2.05.53 - Arreglo Dinámico de Cadenas de Texto ⭐⭐⭐⭐⭐¶
Implementá un arreglo dinámico de cadenas de texto (char **):
Orientación:
Asigná dinámicamente un arreglo de punteros
char **lineasCada línea individual debe alojarse dinámicamente según su longitud exacta
Permití agregar nuevas líneas redimensionando el arreglo de punteros con
reallocEn la función de destrucción, liberá cada cadena antes de liberar el arreglo de punteros
Ejercicio 2.05.54 - Simulador de Memoria ⭐⭐⭐⭐⭐¶
Implementá un simulador que registre todas las asignaciones/liberaciones.
Orientación:
Envolvé
mallocyfreeMantené registro de bloques activos
Detectá double-free y memory leaks
Mostrá estadísticas al final
Ejercicio 2.05.55 - Sistema de Gestión de Memoria Personalizado ⭐⭐⭐⭐⭐¶
Implementá tu propio malloc y free usando sbrk o un buffer grande.
Orientación:
Mantené lista de bloques libres/ocupados
Algoritmo first-fit o best-fit
Metadata en cada bloque (tamaño, ocupado)
Coalescencia de bloques libres adyacentes
Notas Finales¶
Estas consignas cubren todos los aspectos de memoria dinámica: asignación básica, redimensionamiento, estructuras complejas, gestión avanzada y prevención de errores.