Ejercicios Resueltos: Memoria Dinámica
Problemas y soluciones detalladas sobre gestión de memoria en C
Prerrequisitos y Entorno Requerido¶
Para abordar y verificar las soluciones de este módulo, se requiere:
Entorno de Compilación: Compilador GCC 9+ o Clang bajo estándar estricto ISO C11 (
-std=c11 -Wall -Wextra -Werror -pedantic).Primitivas de Heap: Asignación dinámica (
malloc,calloc,realloc), dimensionamiento seguro consizeof(*p)y desasignación simétrica estricta confree.Manejo Defensivo y Fugas: Comprobación sistemática de punteros
NULLante fallos de alocación y validación dinámica de invariantes con AddressSanitizer (-fsanitize=address,undefined).
Acerca de¶
Este archivo contiene problemas prácticos y soluciones canónicas sobre la gestión de
memoria dinámica en el heap utilizando malloc, calloc, realloc y free en C11.
Capítulos de Apunte Correspondientes¶
Ejercicio 2.05c.01 - Asignación Dinámica de Arreglo y Promedio ⭐⭐☆☆☆¶
Solution to Exercise memoria-1
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 63#include <assert.h> #include <math.h> #include <stddef.h> #include <stdlib.h> double *crear_arreglo_reales(size_t cantidad, double valor_inicial) { if (cantidad == 0) { return NULL; } double *arr = malloc(cantidad * sizeof(*arr)); if (arr == NULL) { return NULL; } for (size_t i = 0; i < cantidad; i++) { arr[i] = valor_inicial; } return arr; } double calcular_promedio(const double *arreglo, size_t cantidad) { assert(arreglo != NULL); assert(cantidad > 0); double suma = 0.0; for (size_t i = 0; i < cantidad; i++) { suma += arreglo[i]; } return suma / (double)cantidad; } int main(void) { // Creación normal double *datos = crear_arreglo_reales(4, 10.0); assert(datos != NULL); datos[1] = 20.0; datos[2] = 30.0; datos[3] = 40.0; assert(fabs(calcular_promedio(datos, 4) - 25.0) < 0.001); free(datos); datos = NULL; // Caso tamaño cero assert(crear_arreglo_reales(0, 1.0) == NULL); // Caso un elemento double *unit = crear_arreglo_reales(1, 42.5); assert(unit != NULL); assert(fabs(calcular_promedio(unit, 1) - 42.5) < 0.001); free(unit); unit = NULL; return 0; }
Ejercicio 2.05c.02 - Duplicación de Cadenas en Memoria Dinámica ⭐⭐☆☆☆¶
Solution to Exercise memoria-2
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#include <assert.h> #include <stddef.h> #include <stdlib.h> #include <string.h> char *duplicar_cadena(const char *original) { if (original == NULL) { return NULL; } size_t len = 0; while (original[len] != '\0') { len++; } char *copia = malloc(len + 1); if (copia == NULL) { return NULL; } for (size_t i = 0; i <= len; i++) { copia[i] = original[i]; } return copia; } int main(void) { // Caso normal char *c1 = duplicar_cadena("Estructura de Datos"); assert(c1 != NULL); assert(strcmp(c1, "Estructura de Datos") == 0); free(c1); // Caso vacía char *c2 = duplicar_cadena(""); assert(c2 != NULL); assert(strcmp(c2, "") == 0); free(c2); // Caso nulo assert(duplicar_cadena(NULL) == NULL); return 0; }
Ejercicio 2.05c.03 - Búsqueda y Conteo en Arreglo Dinámico ⭐⭐☆☆☆¶
Solution to Exercise memoria-3
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81#include <assert.h> #include <stddef.h> #include <stdlib.h> int *crear_arreglo_inicializado(size_t tamano, int valor_inicial) { if (tamano == 0) { return NULL; } int *arreglo = malloc(tamano * sizeof(*arreglo)); if (arreglo == NULL) { return NULL; } for (size_t i = 0; i < tamano; i++) { arreglo[i] = valor_inicial; } return arreglo; } int buscar_elemento(const int *arreglo, size_t tamano, int valor) { if (arreglo == NULL) { return -1; } for (size_t i = 0; i < tamano; i++) { if (arreglo[i] == valor) { return (int)i; } } return -1; } size_t contar_ocurrencias(const int *arreglo, size_t tamano, int valor) { if (arreglo == NULL) { return 0; } size_t contador = 0; for (size_t i = 0; i < tamano; i++) { if (arreglo[i] == valor) { contador++; } } return contador; } int main(void) { size_t n = 5; int *arr = crear_arreglo_inicializado(n, 5); assert(arr != NULL); arr[2] = 10; arr[4] = 20; assert(buscar_elemento(arr, n, 10) == 2); assert(contar_ocurrencias(arr, n, 10) == 1); assert(buscar_elemento(arr, n, 5) == 0); assert(contar_ocurrencias(arr, n, 5) == 3); assert(buscar_elemento(arr, n, 99) == -1); assert(contar_ocurrencias(arr, n, 99) == 0); free(arr); return 0; }
Ejercicio 2.05c.04 - Creación y Liberación de Matriz Dinámica ⭐⭐⭐☆☆¶
Solution to Exercise memoria-4
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 63 64 65 66 67 68 69 70 71 72 73 74#include <assert.h> #include <stddef.h> #include <stdlib.h> int **crear_matriz(size_t filas, size_t columnas) { if (filas == 0 || columnas == 0) { return NULL; } int **matriz = malloc(filas * sizeof(*matriz)); if (matriz == NULL) { return NULL; } for (size_t i = 0; i < filas; i++) { matriz[i] = malloc(columnas * sizeof(**matriz)); if (matriz[i] == NULL) { // Desasignar filas previas en caso de falla intermedia for (size_t k = 0; k < i; k++) { free(matriz[k]); } free(matriz); return NULL; } } return matriz; } void liberar_matriz(int **matriz, size_t filas) { if (matriz == NULL) { return; } for (size_t i = 0; i < filas; i++) { free(matriz[i]); } free(matriz); } int main(void) { size_t f = 3; size_t c = 4; int **m = crear_matriz(f, c); assert(m != NULL); for (size_t i = 0; i < f; i++) { for (size_t j = 0; j < c; j++) { m[i][j] = (int)(i * c + j); } } assert(m[0][0] == 0); assert(m[2][3] == 11); liberar_matriz(m, f); assert(crear_matriz(0, 5) == NULL); assert(crear_matriz(5, 0) == NULL); return 0; }
Ejercicio 2.05c.05 - Gestión de Estructura con Miembros Dinámicos ⭐⭐⭐☆☆¶
Solution to Exercise memoria-5
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78#include <assert.h> #include <stddef.h> #include <stdlib.h> #include <string.h> typedef struct { char *nombre; char *apellido; int edad; } persona_t; static char *clonar_texto(const char *src) { if (src == NULL) return NULL; size_t len = strlen(src); char *dest = malloc(len + 1); if (dest != NULL) { memcpy(dest, src, len + 1); } return dest; } persona_t *crear_persona(const char *nombre, const char *apellido, int edad) { if (nombre == NULL || apellido == NULL || edad < 0) { return NULL; } persona_t *p = malloc(sizeof(*p)); if (p == NULL) { return NULL; } p->nombre = clonar_texto(nombre); p->apellido = clonar_texto(apellido); p->edad = edad; if (p->nombre == NULL || p->apellido == NULL) { free(p->nombre); free(p->apellido); free(p); return NULL; } return p; } void destruir_persona(persona_t *p) { if (p == NULL) { return; } free(p->nombre); free(p->apellido); free(p); } int main(void) { persona_t *p = crear_persona("Alan", "Turing", 41); assert(p != NULL); assert(strcmp(p->nombre, "Alan") == 0); assert(strcmp(p->apellido, "Turing") == 0); assert(p->edad == 41); destruir_persona(p); assert(crear_persona(NULL, "Turing", 41) == NULL); assert(crear_persona("Alan", NULL, 41) == NULL); return 0; }
Ejercicio 2.05c.06 - Diagnóstico y Prevención de Fugas de Memoria ⭐⭐⭐☆☆¶
Solution to Exercise memoria-6
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#include <assert.h> #include <stddef.h> #include <stdlib.h> int *crear_arreglo_seguro(size_t tamano) { if (tamano == 0) { return NULL; } int *arr = malloc(tamano * sizeof(*arr)); if (arr == NULL) { return NULL; } for (size_t i = 0; i < tamano; i++) { arr[i] = (int)i; } return arr; } int sumar_elementos(const int *arr, size_t tamano) { if (arr == NULL) { return 0; } int suma = 0; for (size_t i = 0; i < tamano; i++) { suma += arr[i]; } return suma; } int main(void) { int *arr = crear_arreglo_seguro(5); assert(arr != NULL); assert(sumar_elementos(arr, 5) == 10); free(arr); arr = NULL; assert(crear_arreglo_seguro(0) == NULL); return 0; }
Ejercicio 2.05c.07 - Matriz Contigua en Memoria Plana y Transposición In-Place ⭐⭐⭐☆☆¶
Solution to Exercise memoria-7
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#include <assert.h> #include <stddef.h> #include <stdlib.h> int *crear_matriz_contigua(size_t filas, size_t columnas) { if (filas == 0 || columnas == 0) { return NULL; } int *matriz = malloc(filas * columnas * sizeof(*matriz)); return matriz; } void transponer_cuadrada_contigua(int *matriz, size_t n) { if (matriz == NULL || n < 2) { return; } for (size_t i = 0; i < n; i++) { for (size_t j = i + 1; j < n; j++) { size_t idx1 = i * n + j; size_t idx2 = j * n + i; int temp = matriz[idx1]; matriz[idx1] = matriz[idx2]; matriz[idx2] = temp; } } } int main(void) { size_t n = 2; int *m = crear_matriz_contigua(n, n); assert(m != NULL); m[0 * n + 0] = 1; m[0 * n + 1] = 2; m[1 * n + 0] = 3; m[1 * n + 1] = 4; transponer_cuadrada_contigua(m, n); assert(m[0 * n + 0] == 1); assert(m[0 * n + 1] == 3); assert(m[1 * n + 0] == 2); assert(m[1 * n + 1] == 4); free(m); m = NULL; return 0; }