Это полностью зависит от вашей реализации связанного списка.
Возможно несколько возможных реализаций.
- линейный связанный список с внешним указателем на начальный узел
- указатель на NULL, если пуст
- последний узел NULL
- круглые связанные списки с внешним указателем на начальный узел
- если только один элемент, он указывает на себя, а внешний элемент указывает на единственный элемент
- если нет элемента, внешний указатель равен NULL
- круглые связанные списки с одним элементом в качестве элемента head
- если пусто, головной элемент указывает на себя
- заключено в структуру
- одна из приведенных схем ссылок
- с дополнительным указателем конца для более быстрой вставки конца
В зависимости от структуры списка реализация может отличаться.
На общем основании можно сказать, что вы начинаете с указателя H
, который указывает на элемент E
, и этот элемент имеет next
указатель на преемника S
.
Вы правы, установив для H
значение next
. поскольку H
и E
должны быть действительными, ошибки сегментации не должно быть.
В самой простой форме (непроверенный / некомпилированный код - должен просто показывать принцип):
typedef struct ListNode{
void* data,
struct ListNode* next;
}ListNode;
/**
* \brief removes an element from the linked list
*
* \param io_el the 'next' pointer of the previous
* element or the pointer to the head
* \return the pointer to the removed element
*
* \details
* uses the io_el pointer to advance to the next list element and
* sets the io_el pointer to the content of the next pointer of
* this element. This effectivly removes the element from the chain.
* The removed element is returned so that it may be free'd if necessary.
*/
Node* ListDeleteElement(Node** io_el){
Node* res = NULL;
if( io_el && *io_el){
res = *io_el;
*io_el = (*io_el)->next;
}
}
с учетом следующего списка.
Node E1 ,E2,E3;
Node* H = &E1;
E1.next = &E2;
E2.next = &E3;
E3.next = NULL;
// (H = ) E1 -> E2 -> E3 -> NULL
// remove E3;
ListDeleteElement( &(H->next->next) ); // passes pointer to the nextpointer of E2,
// E2.next should be NULL now
// (H = ) E1 -> E2 -> NULL
// remove E1
ListDeleteElement( &H );
// *H should now be E2
// (H = ) E2 -> NULL
// again remove first element
ListDeleteElement( &H );
// (H = ) NULL
Эта реализация опасна - абсолютно необходимо, чтобы переданный указатель являлся указателем на голову или указателем на next
указатель фактического элемента списка.
Передача адресов произвольного указателя в структуру списка приводит к повреждению списка.
Таким образом, этот код должен использоваться как внутренняя вспомогательная функция, которая заключена в более высокоуровневую функцию или должна использоваться в небольших локальных списках, которые не передаются другим частям программы. В этом случае я бы разработал более надежный класс списка.