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 →