Предположим список со структурой
A -> B -> C -> D
Если у вас есть только указатель на B и вы хотите удалить его, вы можете сделать что-то вроде
tempList = B->next;
*B = *tempList;
free(tempList);
Список будет выглядеть как
A -> B -> D
но B будет хранить старое содержимое C, эффективно удаляя то, что было в B. Это не будет работать, если какой-то другой фрагмент кода содержит указатель на C. Это также не будет работать, если вы пытаетесь удалить узел D. Если вы хотите выполнить операцию такого типа, вам нужно построить список с фиктивным хвостовым узлом, который на самом деле не используется, так что вы гарантируете, что ни один полезный узел не будет иметь нулевого следующего указателя. Это также работает лучше для списков, где объем данных, хранящихся в узле, невелик. Структура типа
struct List { struct List *next; MyData *data; };
было бы хорошо, но тот, где это
struct HeavyList { struct HeavyList *next; char data[8192]; };
было бы немного обременительно.