Estructuras de Datos

0x0042 INICIALIZANDO...
0x7ffe-stack
*p = malloc(sizeof(Node))
0x3b2a - heap
ptr -> next = NULL
Unidad 06

Punteros y Memoria Dinámica

En C, la memoria se gestiona principalmente en dos áreas: el Stack (Pila), donde viven las variables locales de tamaño fijo y gestión automática; y el Heap (Montículo), una zona libre y grande donde el programador decide cuándo reservar y liberar memoria manualmente.

Imagen 24. Organización de la memoria RAM: Stack vs Heap

Imagen 24. Organización de la memoria RAM: Stack vs Heap

Diagrama de la RAM: Observa cómo el Stack crece hacia direcciones bajas y el Heap hacia direcciones altas, con un espacio libre en medio.

6.1 Stack vs. Heap: ¿Dónde viven mis datos?
Mirar en YouTube
main.cpp
void funcion() {
// Memoria Estática (Stack)
int x = 10;
int arrayFijo[100];

// Memoria Dinámica (Heap)
// Solo el puntero "ptr" está en el Stack,
// pero apunta a un bloque de 100 enteros en el Heap.
int *ptr = (int*) malloc(100 * sizeof(int));
}
void funcion() {
// Memoria Estática (Stack)
int x = 10;
int arrayFijo[100];

// Memoria Dinámica (Heap)
// Solo el puntero "ptr" está en el Stack,
// pero apunta a un bloque de 100 enteros en el Heap.
int *ptr = (int*) malloc(100 * sizeof(int));
}

Para usar el Heap necesitamos la librería <stdlib.h>. La función principal es "malloc" (memory allocation), que reserva un bloque de bytes consecutivos. Es vital liberar esta memoria con "free" para evitar fugas de memoria (memory leaks).

6.2 (Parte 1) Malloc, Calloc y Free: Asignación Básica
Mirar en YouTube
main.cpp
// Asignar memoria para un array de n enteros
int *arr = (int*) malloc(n * sizeof(int));

if (arr == NULL) {
printf("Error: No hay memoria suficiente");
exit(1);
}

// Usar el array...
// Liberar memoria al terminar
free(arr);
arr = NULL; // Buena práctica para evitar "punteros colgantes"
// Asignar memoria para un array de n enteros
int *arr = (int*) malloc(n * sizeof(int));

if (arr == NULL) {
printf("Error: No hay memoria suficiente");
exit(1);
}

// Usar el array...
// Liberar memoria al terminar
free(arr);
arr = NULL; // Buena práctica para evitar "punteros colgantes"
6.2 (Parte 2) Realloc: Arrays que crecen dinámicamente
Mirar en YouTube
Imagen 25. Comportamiento de realloc en memoria

Imagen 25. Comportamiento de realloc en memoria

Visualización de realloc: Si hay espacio contiguo, expande el bloque. Si no, busca un nuevo espacio, copia los datos y libera el anterior automáticamente.

Los punteros son variables que guardan direcciones numéricas. Lo interesante es que sumar 1 a un puntero no suma 1 byte, sino "sizeof(tipo)" bytes. Si un puntero int apunta a la dirección 1000, "ptr + 1" apuntará a 1004 (en arquitecturas de 32 bits).

main.cpp
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr;

printf("Tercer elemento: %d", *(ptr + 2)); // Imprime 30

// Recorrer sin índices "i"
for (int *p = arr; p < arr + 5; p++) {
printf("%d ", *p);
}
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr;

printf("Tercer elemento: %d", *(ptr + 2)); // Imprime 30

// Recorrer sin índices "i"
for (int *p = arr; p < arr + 5; p++) {
printf("%d ", *p);
}
6.3 Aritmética de Punteros
Mirar en YouTube

El verdadero poder de los punteros surge cuando una estructura contiene un puntero a otra estructura de su mismo tipo. Esto permite crear "Nodos" que se enlazan entre sí, formando cadenas de datos infinitas (listas, árboles).

6.4 Intro a Estructuras Dinámicas (El Nodo)
Mirar en YouTube
main.cpp
struct Nodo {
int dato;
struct Nodo* siguiente;
};

int main() {
// Crear nodos en Heap
struct Nodo* nodo1 = (struct Nodo*) malloc(sizeof(struct Nodo));
struct Nodo* nodo2 = (struct Nodo*) malloc(sizeof(struct Nodo));

// Asignar datos y enlazar
nodo1->dato = 5;
nodo1->siguiente = nodo2; // Enlace
nodo2->dato = 10;
nodo2->siguiente = NULL; // Fin de la lista
}
struct Nodo {
int dato;
struct Nodo* siguiente;
};

int main() {
// Crear nodos en Heap
struct Nodo* nodo1 = (struct Nodo*) malloc(sizeof(struct Nodo));
struct Nodo* nodo2 = (struct Nodo*) malloc(sizeof(struct Nodo));

// Asignar datos y enlazar
nodo1->dato = 5;
nodo1->siguiente = nodo2; // Enlace
nodo2->dato = 10;
nodo2->siguiente = NULL; // Fin de la lista
}