c круговой двойной связанный список delete_node - повторяет обход удаленного узла при первом проходе после удаления
Все, в GNU c, у меня есть круговой двусвязный список, на котором я пытаюсь реализовать функцию delete_node. Он работает нормально для всех узлов, кроме узла 0. Он удаляет (free ()) узел 0, но при первом просмотре списка после удаления узла 0 он все еще присутствует для первого прохода, вызывая условное прекращение итерации для потерпеть поражение. Основы реализации:
struct record
{
char *line;
int lineno;
int linetype;
struct record *prev;
struct record *next;
};
typedef struct record rec;
void
iterfwd (rec *list) {
rec *iter = list; // second copy to iterate list
if (iter == NULL) {
fprintf (stdout,"%s(), The list is empty\n",__func__);
} else {
do {
printf ("%2d - prev: %p cur: %p next: %p\n", iter->lineno, iter->prev, iter, iter->next);
iter = iter->next;
} while (iter != list);
}
}
void
delete_node (rec *list, int num) {
rec *iter = list; // second copy to iterate list
int cnt = 0;
int found = 0;
if (iter == NULL) {
fprintf (stdout,"%s(), The list is empty\n",__func__);
} else {
// traverse list forward (check cnt == num, else if end -> Out Of Range)
do {
if (cnt == num) {
found=1;
(iter->prev)->next = iter->next;
(iter->next)->prev = iter->prev;
free (iter);
break;
}
iter = iter-> next;
cnt++;
} while (iter != list);
if (found != 1) {
fprintf (stderr, "%s(), Error: record to delete is out of range (%d)\n", __func__, num);
}
}
}
int main (int argc, char *argv[]) {
struct record *textfile = NULL; // instance of record, pointer to list
int node = 0;
node = (argc >= 2) ? atoi (argv[1]) : 0;
textfile = fillrecord (); // fill textfile circular linked-list
iterfwd (textfile);
delete_node (textfile, node);
iterfwd (textfile);
return 0;
}
Полный список здесь:http://www.3111skyline.com/dl/dev/prg/src/ll-double-cir.c.txt
Список заполнен 50 записями данных для тестирования, и я вставил операторы printf для подтверждения операций с указателями. Удаление любого узла, кроме узла 0, работает должным образом (ниже приведены адреса указателей для iter-> prev, iter, iter-> next для затронутых строк [pre- и post-delete] для удаления узла 10):
9 - prev: 0x603490 cur: 0x603520 next: 0x6035b0
10 - prev: 0x603520 cur: 0x6035b0 next: 0x603640 <-- delete_node
11 - prev: 0x6035b0 cur: 0x603640 next: 0x6036d0
9 - prev: 0x603490 cur: 0x603520 next: 0x603640
10 - prev: 0x603520 cur: 0x6035b0 next: 0x603640 <-- (node deleted)
11 - prev: 0x603520 cur: 0x603640 next: 0x6036d0
На следующем ходу списка все работает как положено:
7 - prev: 0x603370 cur: 0x603400 next: 0x603490
8 - prev: 0x603400 cur: 0x603490 next: 0x603520
9 - prev: 0x603490 cur: 0x603520 next: 0x603640
11 - prev: 0x603520 cur: 0x603640 next: 0x6036d0
12 - prev: 0x603640 cur: 0x6036d0 next: 0x603760
Однако, если узел 0 удален, delete_node правильно обрабатывает указатели:
49 - prev: 0x604b10 cur: 0x604ba0 next: 0x603010
0 - prev: 0x604ba0 cur: 0x603010 next: 0x6030a0 <-- delete_node
1 - prev: 0x603010 cur: 0x6030a0 next: 0x603130
49 - prev: 0x604b10 cur: 0x604ba0 next: 0x6030a0
0 - prev: 0x604ba0 cur: 0x603010 next: 0x6030a0 <-- (node deleted)
1 - prev: 0x604ba0 cur: 0x6030a0 next: 0x603130
Но затем при первой попытке просмотреть список после удаления узел 0 появляется при первом проходе, вызывая сбой условий итератора 'while (iter! = List)' и застревание в цикле:
0 - prev: 0x604ba0 cur: 0x603010 next: 0x6030a0
1 - prev: 0x604ba0 cur: 0x6030a0 next: 0x603130
2 - prev: 0x6030a0 cur: 0x603130 next: 0x6031c0
3 - prev: 0x603130 cur: 0x6031c0 next: 0x603250
4 - prev: 0x6031c0 cur: 0x603250 next: 0x6032e0
<snip>
47 - prev: 0x6049f0 cur: 0x604a80 next: 0x604b10
48 - prev: 0x604a80 cur: 0x604b10 next: 0x604ba0
49 - prev: 0x604b10 cur: 0x604ba0 next: 0x6030a0
1 - prev: 0x604ba0 cur: 0x6030a0 next: 0x603130
2 - prev: 0x6030a0 cur: 0x603130 next: 0x6031c0
3 - prev: 0x603130 cur: 0x6031c0 next: 0x603250
Как показано выше, после того, как итератор проходит через 0-49, удаленный узел 0 исчезает и снова начинает правильно проходить через 1-49, но в этот момент он находится в цикле, потому что условное (iter! = List) всегда истинно (узел 0 исчезает, препятствуя тому, чтобы iter был в любом равном списке). Это чистый круговой список, нет узлов HEAD или TAIL, для которых установлено значение null, end-> next указывает на начало списка, а first-> prev указывает на конец. В чем заключается хитрость работы функции delete_node () для узла 0, при которой первая итерация после удаления начинается с 1, а не со старого 0, который затем исчезает?