Las listas enlazadas combinan punteros, memoria dinámica y lógica de enlaces. Esta mezcla genera errores frecuentes que pueden causar fallas difíciles de depurar. A continuación se describen los más habituales y cómo prevenirlos.
Un puntero no inicializado contiene basura y puede apuntar a direcciones aleatorias. Esto causa comportamiento indefinido al primer acceso.
Nodo *cabeza; /* ERROR: valor indefinido */
cabeza->valor = 10; /* acceso inválido */
/* Solución */
Nodo *cabeza = NULL;
if (!cabeza) {
cabeza = malloc(sizeof(Nodo));
}
Siempre inicializa punteros en NULL y valida el resultado de malloc antes de usarlos.
Si el puntero a la cabeza se reasigna sin guardar la referencia original, la lista queda inaccesible, provocando fugas de memoria.
Nodo *cabeza = lista;
cabeza = cabeza->sig; /* Se "pierde" el nodo inicial si no se guarda */
/* Solución correcta */
Nodo *actual = cabeza;
cabeza = cabeza->sig;
free(actual);
Ocurren cuando los nodos se reservan con malloc pero no se liberan. Con el tiempo, la memoria del proceso crece hasta agotar los recursos.
void lista_insertar(Lista *lista, int valor) {
Nodo *n = malloc(sizeof(Nodo));
/* ... */
}
/* Si no hay una función lista_limpiar, los nodos quedan sin liberar */
void lista_limpiar(Lista *lista) {
Nodo *reco = lista->cabeza;
while (reco) {
Nodo *tmp = reco->sig;
free(reco);
reco = tmp;
}
lista->cabeza = NULL;
}
Intentar usar un nodo después de liberar su memoria genera errores impredecibles (“use-after-free”).
Nodo *victima = lista->cabeza;
lista->cabeza = victima->sig;
free(victima);
printf("%d", victima->valor); /* ERROR: memoria liberada */
/* Solución */
int valor = victima->valor;
free(victima);
printf("%d", valor);
Al manipular punteros, un error puede conectar un nodo consigo mismo o saltarse parte de la lista, creando un ciclo que provoca recorridos infinitos.
reco->sig = reco; /* ERROR: ciclo inmediato */
/* Verificar siempre antes de asignar */
if (reco->sig) {
/* lógica normal */
}
Para detectar ciclos involuntarios, se pueden usar algoritmos como “tortuga y liebre” (Floyd) durante la depuración.
Un puntero salvaje apunta a una región aleatoria de memoria debido a cast incorrectos, memoria liberada o falta de inicialización. Produce fallas sutiles o corruptelas.
Nodo *reco = (Nodo *)0x1234; /* Dirección arbitraria - ERROR */
/* Buenas prácticas */
Nodo *reco = NULL;
/* ... asignar reco con una dirección válida ... */
if (reco) {
/* usar el puntero */
}
malloc.