Lección 9 · 9 de 20
Una lista enlazada · C
Programe en C una lista enlazada de tareas: nodos en el montón, añadir al final y al principio, borrar por id y liberar la lista entera.

Una lista enlazada es una cadena de nodos: cada Task guarda sus datos y un puntero next al siguiente, y el último tiene next a NULL. A diferencia de un array, añadir o quitar en medio no obliga a mover nada: basta con cambiar un puntero.
new_task reserva un nodo con malloc, lo rellena y lo enlaza delante de next. Con NULL crea un nodo suelto; con la lista actual, como en todo = new_task(4, "Server", todo), lo pone al principio, que es la operación más rápida de una lista.
append y remove_id usan un puntero a puntero, Task **link. Empieza apuntando a todo y, en cada paso, pasa a apuntar al campo next del nodo actual. Así no hay caso especial para el primer nodo: cuando el bucle para, *link es justo el puntero que hay que cambiar, sea la cabeza o el next de otro nodo.
Para borrar, remove_id guarda el nodo en gone, hace que *link salte a gone->next y libera gone. En la salida, la tarea 2 desaparece y las demás siguen enlazadas.
Al final, el bucle while libera la lista entera: guarda next antes del free, porque después de liberar un nodo ya no se puede leer su campo next.
Código · main.c
#include <stdio.h>#include <stdlib.h>typedef struct Task { int id; const char *title; struct Task *next; } Task;// A new node on the heap, linked in front of `next` (NULL: the end).Task *new_task(int id, const char *title, Task *next) { Task *t = malloc(sizeof *t); if (!t) exit(EXIT_FAILURE); t->id = id; t->title = title; t->next = next; return t;}// Task **link points at the pointer we may change: head or some ->next.void append(Task **link, Task *t) { while (*link) link = &(*link)->next; *link = t;}void remove_id(Task **link, int id) { while (*link && (*link)->id != id) link = &(*link)->next; if (*link) { Task *gone = *link; *link = gone->next; free(gone); }}void print(const char *label, const Task *t) { for (printf("%-9s", label); t; t = t->next) printf(" [%d %s]", t->id, t->title); printf("\n");}int main(void) { Task *todo = NULL; // an empty list append(&todo, new_task(1, "Invoice", NULL)); append(&todo, new_task(2, "Call Ana", NULL)); append(&todo, new_task(3, "Backup", NULL)); print("Start:", todo); remove_id(&todo, 2); print("Done 2:", todo); todo = new_task(4, "Server", todo); print("Urgent:", todo); while (todo) { Task *next = todo->next; free(todo); todo = next; } // free all return 0;}Salida · cc main.c -o main && ./main
Start: [1 Invoice] [2 Call Ana] [3 Backup] Done 2: [1 Invoice] [3 Backup] Urgent: [4 Server] [1 Invoice] [3 Backup]
Para recordar
- Cada nodo apunta al siguiente; el último, a
NULL. - Insertar al principio no recorre nada.
- Con
Task **linkse modifica la cabeza o cualquiernextsin casos especiales. - Al liberar, guarde
nextantes defree.
Ejercicio
Escriba int count(const Task *t) y Task *find(Task *t, int id), y use find para cambiar el título de la tarea 3 a "Backup NAS".