. (Когда я удаляю хвостовой узел, ссылка предыдущего теперь просто указывает на какую-то случайную часть памяти? В этом ли проблема? И почему бесконечный цикл?
выглядит так:
int removetail(Node*& head)
{
// base cases elided
Node* p=NULL;
p=head;
while(p->link!=NULL) p=p->link;
x=p->n;
delete p;
return x;
}
Предыдущая ссылка, указывающая на p, который вы удаляете, по-прежнему указывает на p. Плохой. Это должно быть что-то вроде этого:
int removetail(Node*& head)
{
// base cases elided
Node* p=NULL;
p=head;
while(p->link->link!=NULL) p=p->link;
x=p->link->n;
delete p->link;
p->link = NULL; // maintain linked list integrity
return x;
}
Это безопасно сделать (при условии, что память не повреждена по другим причинам), потому что вы уже проверили, если head==NULL
и head->link == NULL
в одном из базовых случаев, поэтому начальный вызов p-> link- > link = head-> link-> link не даст вам неправильного доступа к указателю. Если head-> link-> link == NULL, это нормально.
А почему бесконечный цикл?
Интересный вопрос.
Для немного ошибочного философского объяснения: если вы не получите ошибку доступа к недопустимой памяти, вызванную обращением к неверному указателю, вы говорите о значении указателя, которое случайно указывает куда-то. Реальная память конечна, поэтому любая последовательность ссылок на указатели в конечном наборе должна повторяться в некоторой точке цикла (иначе набор не будет конечным). Конечно, это может включать NULL, который остановит бесконечный цикл.
Скорее всего, вы столкнулись с каким-то неправильным шаблоном памяти, зарезервированным диспетчером памяти ОС, например 0xcdcdcdcd, который указывает на 0xcdcdcdcd. В этом случае это плохой выбор: шаблоны памяти по умолчанию, вероятно, должны быть спроектированы так, чтобы, если они отображаются в указателе, они могли вызвать исключение плохой памяти.
Вы можете остановить программу в отладчике и сказать нам, что означает значение указателя, и это ответило бы на эту часть вопроса.