← C EspañolChapter 09 of 13

Asignación de Memoria Dinámica

## Objetivos de Aprendizaje - Comprender pila vs heap - Dominar malloc, calloc, realloc, free - Aprender errores comunes de memoria - Trabajar con arreglos dinámicos ## Diseño de Memoria ```text +------------------+ Dirección Alta | Pila | Variables locales, llamadas a funciones | | | | v | | | | ^ | | | | | Heap | Asignación dinámica (malloc) | | +------------------+ Dirección Baja | Sin Inicializar| | Inicializado | | Segmento de Código| +------------------+ ``` ## Pila vs Heap ### Pila (Automática) ```c void function(void) { int arr[1000]; // Asignado en la pila // Liberado automáticamente cuando la función retorna } ``` ### Heap (Dinámica) ```c void function(void) { int *arr = malloc(1000 * sizeof(int)); // Asignado en el heap // ¡Debe liberarse manualmente! free(arr); } ``` ## malloc ### Uso Básico ```c #include int *ptr = (int*)malloc(sizeof(int)); if (ptr == NULL) { // Manejar fallo de asignación return 1; } *ptr = 42; printf("%d\n", *ptr); free(ptr); ptr = NULL; ``` ### Asignar Arreglo ```c int *arr = (int*)malloc(5 * sizeof(int)); if (arr == NULL) { return 1; } for (int i = 0; i < 5; i++) { arr[i] = i * 10; } free(arr); ``` ### malloc No Inicializa ```c int *arr = (int*)malloc(5 * sizeof(int)); // Los valores están SIN INICIALIZAR (basura) int *arr2 = (int*)calloc(5, sizeof(int)); // Inicializado a cero ``` ## calloc ### Sintaxis de calloc ```c int *arr = (int*)calloc(5, sizeof(int)); // Los 5 elementos son 0 for (int i = 0; i < 5; i++) { printf("%d ", arr[i]); // 0 0 0 0 0 } free(arr); ``` ### Sintaxis ```c void *calloc(size_t num, size_t size); // num: número de elementos // size: tamaño de cada elemento ``` ## realloc ### Redimensionar Memoria ```c int *arr = (int*)malloc(5 * sizeof(int)); // Llenar arreglo for (int i = 0; i < 5; i++) { arr[i] = i; } // Redimensionar a 10 elementos int *newArr = (int*)realloc(arr, 10 * sizeof(int)); if (newArr == NULL) { free(arr); // Original todavía válido return 1; } arr = newArr; // Actualizar puntero // Nuevos elementos están sin inicializar for (int i = 5; i < 10; i++) { arr[i] = i * 10; } free(arr); ``` ### Reducir Memoria ```c int *arr = (int*)malloc(10 * sizeof(int)); // ... usar primeros 5 elementos ... int *newArr = (int*)realloc(arr, 5 * sizeof(int)); // Puede reducirse de forma segura incluso si newArr == arr ``` ### Patrón Común: Crecer Arreglo ```c int *arr = NULL; int size = 0; int capacity = 0; int value; while (scanf("%d", &value) == 1) { if (size >= capacity) { capacity = capacity == 0 ? 1 : capacity * 2; int *newArr = (int*)realloc(arr, capacity * sizeof(int)); if (newArr == NULL) { free(arr); return 1; } arr = newArr; } arr[size++] = value; } ``` ## free ### Uso Básico de free ```c int *ptr = (int*)malloc(sizeof(int)); *ptr = 42; free(ptr); ptr = NULL; // Siempre establecer a NULL después de free ``` ### free(NULL) es Seguro ```c int *ptr = NULL; free(ptr); // No-op, perfectamente seguro ``` ## Errores Comunes ### Fuga de Memoria ```c void leak(void) { int *ptr = malloc(sizeof(int)); *ptr = 42; // ¡Falta free(ptr)! } ``` **Detectado con valgrind:** ```bash valgrind --leak-check=full ./program ``` ### Doble Liberación ```c int *ptr = malloc(sizeof(int)); free(ptr); free(ptr); // ¡Comportamiento indefinido! ``` ### Uso Después de Liberación (Puntero Colgante) ```c int *ptr = malloc(sizeof(int)); *ptr = 42; free(ptr); printf("%d\n", *ptr); // ¡Comportamiento indefinido! ``` ### No Verificar NULL ```c int *ptr = (int*)malloc(sizeof(int)); *ptr = 42; // ¡Falla si malloc retorna NULL! ``` ### Liberación Parcial ```c int **grid = (int**)malloc(10 * sizeof(int*)); for (int i = 0; i < 10; i++) { grid[i] = (int*)malloc(10 * sizeof(int)); } // Incorrecto: solo libera el arreglo externo free(grid); // Correcto: liberar arreglos internos primero for (int i = 0; i < 10; i++) { free(grid[i]); } free(grid); ``` ## Arreglos 2D Dinámicos ### Arreglo de Punteros ```c int **createMatrix(int rows, int cols) { int **matrix = (int**)malloc(rows * sizeof(int*)); if (matrix == NULL) return NULL; for (int i = 0; i < rows; i++) { matrix[i] = (int*)malloc(cols * sizeof(int)); if (matrix[i] == NULL) { // Limpieza en caso de fallo for (int j = 0; j < i; j++) { free(matrix[j]); } free(matrix); return NULL; } } return matrix; } void freeMatrix(int **matrix, int rows) { for (int i = 0; i < rows; i++) { free(matrix[i]); } free(matrix); } ``` ### Arreglo 2D Contiguo (Mejor) ```c int **createMatrix(int rows, int cols) { int **matrix = (int**)malloc(rows * sizeof(int*)); int *data = (int*)malloc(rows * cols * sizeof(int)); if (matrix == NULL || data == NULL) { free(matrix); free(data); return NULL; } for (int i = 0; i < rows; i++) { matrix[i] = data + i * cols; } return matrix; } ``` ## Asignando Cadenas ```c char *strdup(const char *s) { size_t len = strlen(s) + 1; char *copy = (char*)malloc(len); if (copy) { memcpy(copy, s, len); } return copy; } // Uso char *name = strdup("Hello"); free(name); ``` ## Miembros de Arreglo Flexibles ```c struct Person { size_t nameLength; char name[]; // Miembro de arreglo flexible }; struct Person *p = malloc(sizeof(struct Person) + 21); p->nameLength = 20; strcpy(p->name, "Alice"); free(p); ``` ## Mejores Prácticas de Gestión de Memoria ### Siempre Inicializar ```c int *ptr = (int*)calloc(n, sizeof(int)); // Inicializado a cero ``` ### Siempre Verificar ```c int *ptr = (int*)malloc(sizeof(int)); if (ptr == NULL) { // Manejar error return; } ``` ### Siempre Liberar ```c free(ptr); ptr = NULL; ``` ### Herramienta: valgrind ```bash valgrind --leak-check=full --show-leak-kinds=all ./program ``` ## Resumen - Pila: automática, rápida, tamaño limitado - Heap: manual, flexible, más grande - `malloc(size)`: asigna memoria cruda - `calloc(n, size)`: asigna memoria inicializada a cero - `realloc(ptr, newSize)`: redimensiona memoria - `free(ptr)`: libera memoria - Siempre verificar NULL - Siempre establecer puntero a NULL después de free - Usar valgrind para detectar fugas

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →