Para gestionar un historial de URLs y simular la función atrás de un navegador web, podemos implementar una pila en C utilizando listas enlazadas. La idea es almacenar cada URL visitada en un nodo, y así, al pulsar atrás, simplemente recuperamos la última URL almacenada en la pila.
Primero, definimos un tipo URL como un puntero a char, que representará nuestras cadenas de texto con las direcciones web. Luego, creamos una estructura nodo que contendrá una URL y un puntero al siguiente nodo, formando así la lista enlazada que representará la pila.
typedef char* URL;
typedef struct nodo {
URL url;
struct nodo* siguiente;
} nodo;
Para manejar la pila, definimos una estructura que contiene un puntero a la cima de la pila y un campo para la longitud, que nos ayudará a controlar cuántos elementos hay en ella.
typedef struct pila {
nodo* cima;
int longitud;
} pila;
La operación para crear un nuevo nodo recibe una URL, reserva memoria dinámica para el nodo, asigna la URL y establece el puntero siguiente a NULL.
#include <stdlib.h>
nodo* crearNodo(URL url) {
nodo* nuevo = (nodo*) malloc(sizeof(nodo));
if (nuevo == NULL) return NULL; // Comprobación básica de malloc
nuevo->url = url;
nuevo->siguiente = NULL;
return nuevo;
}
Para evitar fugas de memoria, es fundamental destruir los nodos cuando ya no los necesitemos. La función para destruir un nodo libera la memoria asignada y asegura que el puntero siguiente no cause problemas.
void destruirNodo(nodo* n) {
if (n == NULL) return;
n->siguiente = NULL;
free(n);
}
La operación de apilar consiste en crear un nuevo nodo con la URL dada y colocarlo en la cima de la pila. Para ello, el nuevo nodo apunta al nodo que actualmente está en la cima, y luego actualizamos la cima para que sea el nuevo nodo. Además, incrementamos la longitud de la pila.
void apilar(pila* p, URL url) {
nodo* nuevo = crearNodo(url);
if (nuevo == NULL) return; // Manejo básico de error
nuevo->siguiente = p->cima;
p->cima = nuevo;
p->longitud++;
}
Para desapilar, primero verificamos que la pila no esté vacía. Si tiene elementos, guardamos el nodo de la cima, actualizamos la cima para que apunte al siguiente nodo, decrementamos la longitud y destruimos el nodo que hemos desapilado.
void desapilar(pila* p) {
if (p->cima == NULL) return; // Pila vacía, nada que desapilar
nodo* aEliminar = p->cima;
p->cima = p->cima->siguiente;
p->longitud--;
destruirNodo(aEliminar);
}
Para consultar la URL en la cima de la pila, simplemente devolvemos la URL almacenada en el nodo de la cima, siempre que la pila no esté vacía.
URL cima(pila* p) {
if (p->cima == NULL) return NULL; // Pila vacía
return p->cima->url;
}
Crear una pila nueva implica reservar memoria para la estructura pila, inicializar la cima a NULL y la longitud a cero.
pila* crearPila() {
pila* p = (pila*) malloc(sizeof(pila));
if (p == NULL) return NULL; // Manejo básico de error
p->cima = NULL;
p->longitud = 0;
return p;
}
Para destruir una pila, debemos desapilar todos sus elementos para liberar la memoria de cada nodo y luego liberar la memoria de la propia estructura pila.
void destruirPila(pila* p) {
while (p->cima != NULL) {
desapilar(p);
}
free(p);
}
Con la longitud almacenada en la estructura, obtener el número de elementos es tan sencillo como devolver ese valor.
int longitud(pila* p) {
return p->longitud;
}
Y para saber si la pila está vacía, comprobamos si la longitud es cero.
int estaVacia(pila* p) {
return p->longitud == 0;
}
Esta implementación nos permite gestionar un historial de URLs de forma eficiente, con operaciones básicas para apilar, desapilar y consultar la cima, además de controlar la memoria para evitar fugas. Podemos extenderla para añadir funcionalidades como acceder a elementos intermedios o vaciar la pila completamente, pero con estas bases ya tenemos una pila funcional que simula el comportamiento del botón atrás en un navegador web.