C ++ не является контекстно-свободным. Я узнал это некоторое время назад в лекции компиляторов. Быстрый поиск дал эту ссылку, где раздел «Синтаксис или семантика» объясняет, почему C и C ++ не являются контекстно-свободными:
Обсуждение Википедии: Грамматика без контекста
С уважением,
Ованес
Сначала в connectedList :: addNode
, у вас есть конструкция if (head = NULL)
, которая завершится присвоением head
; вам нужен оператор ==
.
Во-вторых, о строке:
head = &(Node (value, NULL));
По несколько не интуитивным причинам это не сработает. Вы получите ссылку на узел
, но этот узел выйдет из области видимости, как только метод завершится, и попытки ссылаться на него приведут к ошибке сегментации. Вам необходимо использовать оператор new
(такой же, как и в другой аналогичной строке):
head = new Node(value, NULL);
Если вы добавляете метод удаления узла, убедитесь, что вы удалили
узел, затем - он не будет автоматически обрабатываться сборщиком мусора, как в Java.
Боковая панель: Подумайте, что происходит следующим образом: когда вы выполняете
Node (value, NULL)
, вы используете временная переменная, объявленная так:Node hiddenTempNode (значение, NULL);
При этом не выделяется место для объекта где-либо, кроме стека - это очень похоже на выделение места для
int
иузла *
в стеке как отдельных переменных. В результате, как только вы выйдете из метода, объект исчезнет, и указатель на него будет делать странные вещи при использовании.
В-третьих, будьте осторожны: вы можете установить next = NULL
в вашем однопараметрический конструктор, чтобы всегда иметь значение. Аналогично для вашего конструктора по умолчанию.
Четвертый: ваш метод connectedList :: print
зацикливается до тех пор, пока p-> next
не станет NULL
и не распечатает значение p-> следующий
; те появления p->
Вы не распределяете память. Вы должны использовать new для ее распределения.
Еще одна ошибка в if (head = NULL), она должна быть if (head == NULL)
void addNode(int value){
Node *p;
if(head == NULL)
head = new Node (value, NULL);
else{
p=head;
while(p->next !=NULL)
p=p->next;
p->next = new Node (value, NULL);
}
}
вы берете адрес переменных в стеке
head = &(Node (value, NULL));
следует изменить на
head = new Node(value, NULL);
, то же самое для кода p-> next. Затем вы захотите удалить эти узлы в своем деструкторе.
Что касается печати, попробуйте
while(p != NULL)
{
cout << p->data << "\n";
p = p->next;
}
Для начала
if(head = NULL)
- это задание, а не проверка на равенство. Измените его на
if(head == NULL)
Во-вторых,
head = &(Node (value, NULL));
Не имеет смысла * измените это на
head = new Node (value, NULL);
* это фактически создает временный объект, дает вам адрес, а затем уничтожает этот вновь созданный объект.
В-третьих,
Node(int x) { data = x; }
] Оставьте следующий
без значения, измените эту строку на
Node(int x) { data = x; next = NULL; }
Вы выделяете пространство для узлов в стеке и получаете его адрес, который исчезнет, как только блок заканчивается и, следовательно, адрес будет признан недействительным. Вы должны выделять узлы, используя вместо этого оператор new
в куче:
Node* node = new Node(value, NULL);
Вы должны освободить все, что вы размещаете в куче, как только оно вам не понадобится, чтобы предотвратить утечку памяти:
delete node;
Я хотел бы добавить две проблемы, которые еще не упоминались:
Ваш оператор удаления на самом деле не выполняет никакой очистки. К тому времени, когда вы назовете это p == null. Если вы хотите очистить список, вам нужно будет реализовать отдельный метод для перебора и удаления каждого узла.
Что-то вроде этого:
void ClearList ()
{
Node * c = head;
Node * n;
while (c != NULL)
{
n = c->next;
delete c;
c = n;
}
}
Теперь код работает, но пытается используйте
delete p;
в конце connectedList :: addNode приводит к ошибке сегментации на время выполнения. Просто любопытно, знал ли кто почему?
Что ж, это проблема, потому что цель функции добавления узла состояла в том, чтобы динамически выделить новый узел в конце LinkedList. Итак, вы делаете это правильно, теперь поставив 'delete p;' вы удаляете только что добавленный узел (что, как я полагаю, вам на самом деле не нужно). Однако, чтобы ответить на ваш вопрос, почему это вызывает ошибку сегментации:
Вы добавляете узел, вы говорите head указать на этот новый узел. Теперь вы удаляете этот новый узел, не сообщая head, что он снова должен указывать на NULL. Таким образом, в следующий раз, когда вы добавите узел или попытаетесь распечатать свой список, он немедленно попытается посмотреть, на что указывает голова, которая на самом деле является освобожденной (удаленной) памятью, kaboom?
Правильное (или хотя бы одно правильное) использование delete в вашем списке - это деструктор,
Решение: не создавайте собственный связанный список. Используйте тот, который предоставляется стандартной библиотекой.