I have created this function to recursively delete nodes from a doubly linked list. The issue here is that based on the call stack, it starts from the second so it does not delete the entire list. I can delete the remaining node from the method where I'm calling this but there should be a way around that. Is there a way of resolving this issue?
void RecursiveClear(const Node* _curr) {
if(_curr != nullptr) {
//_curr->prev = _curr;
_curr = _curr->next;
RecursiveClear(_curr);
}
if (_curr != nullptr) {
delete _curr;
}
}
First: Don't use a leading _.
You modify _curr in the function so by the time you end up at the delete the original pointer is gone. So don't do that, just call the function wiht the next value without modifying the local vbariable:
RecursiveClear(_curr->next);
You also shouldn't do a recursion like that because lists can be long. Your code is not tail recursive. Every node in the list will use up a little bit of stack space. For long lists this will overflow the stack and crash.
Use a temporary so you can reorder the operations to be tail recursive:
void RecursiveClear(const Node* curr) {
if (curr != nullptr) {
const Node *next = curr->next;
delete curr;
RecursiveClear(next);
}
}
Related
I'm stuck on a linked list destructor for my class. This is what I have here:
LinkedList::~LinkedList()
{
LinkedList *forward = nullptr;
LinkedList *current = this;
//iterate through list, deleting each element as we go
while (current != nullptr)
{
//set next pointer to current's next
forward = current->next;
delete current; //delete the current memory
current = forward; //reset current to next's pointer
}
}
When I run it, I get a seg fault. I only want to delete just one node from my linked list. Is that possible? Also, I wasn't given a "head" pointer as I was used to from other lists, so I used "this" instead, does that work?
Aka - the .cpp is finding the spot in the linked list to delete, reorganizing the next pointers around it, and then deleting the node (which calls this destructor)
(when I run my program with an empty destructor, it prints out fine, but of course there are memory leaks)
Any help is appreciated!
by definition delete calls LinkedList::~LinkedList, so you have several (in fact infinite) calls to it because of the loop calling delete, so you access to already deleted element with an undefined behavior
just do
LinkedList::~LinkedList()
{
if (next != nullptr)
delete next;
}
or just
LinkedList::~LinkedList()
{
delete next; // delete on nullptr does nothing
}
even personally I prefer to compare to nullptr first
I argee with bruno.
Besides, when you want to delete a node and you don't have the pointer to head, you need a double-linked list.
The double-linked list has two pointers to its prev and next node.
when you need to delete a node, like this:
ListNode* p;
if(p->pre)
p->pre->nxt = p->nxt;
if(p->nxt)
p->nxt->pre = p->pre;
p->nxt = p->pre = NULL;
delete p;
I'm having a problem in a function that deletes an element in a singly linked list. The element needs to be deleted conditionnaly with the function ShouldDelete().
I haven't found a similar request in C++ in the forums so any help would be appreciated. It seems that the following code does not work 100% of the time.
void SinglyLinkedList::DeleteObjects(Node *pStartPtr)
{
Node *pPtr = pStartPtr;
Node *temp;
while(pPtr != nullptr)
{
temp = pPtr->next;
if (pPtr->ShouldDelete())
{
delete pPtr;
pPtr = temp;
if(temp != nullptr)
{
pPtr->next = temp->next;
}
}
pPtr = temp;
}
}
Any thoughts ?
Thanks!
As a general C++ advice, I would use std::list instead of a DIY list implementation, but since I wrote quite some list logic myself in the old C-days, I'll give it a go.
There are 2 essential problems with your code.
First of all, whenever removing an element from a single-linked list, you should set the next pointer of the previous element to the next of the deleted one. You can do something like this:
Node *previousNode = …;
while(pPtr != nullptr)
{
Node *nextNode = pPtr->next;
if (pPtr->ShouldDelete())
{
delete pPtr;
previousNode->next = nextNode;
}
else
{
previousNode = pPtr;
}
pPtr = nextNode;
}
Notice that no specific if-tests within the for-loop on nullptr are needed. You should tell the previous node that it now points to the next of the deleted one. If there is no next one, the previous->next will just point to a nullptr, indicating the end of the list.
The second problem is that you don't have any clear 'start of the list'. In my example code above, it becomes quite hard to indicate what the previousNode is. Is it a nullptr? But what if we remove the first element?
You could easily add logic here to indicate keep track of the first element, initialize previousNode to nullptr, and if the first is deleted, just don't set previousNode->next' and keep previousNode equal tonullptr` in that case, but what about the caller? How can the caller know that the first element has been deleted and the list now starts later.
My preferred solution is to have a separate List struct/class, and keep the start of the list (the first Node) as a member in the List struct/class. Instead of passing the startNode to the function, you should pass the List instance.
The code in the while-loop now becomes a bit longer, since you need to adapt previousNode->next=nextNode to this:
if (previousNode)
previousNode->next = nextNode;
else
list->firstNode = nextNode;
If you don't want to introduce a new List struct/class, you could also return the new firstNode as return value from your function, like this:
if (previousNode)
previousNode->next = nextNode;
else
startNode = nextNode;
…
return startNode;
Notice that this second approach only works if the caller if the function is also the one maintaining the list, and there are no other places pointing to the startNode.
In any case, if multithreading is involved, you probably want a decent List class with a kind of mutex (ideally std::list decorated with a mutex).
In function given below, I simply delete the head-pointer of the list and set head pointer to nullptr (im setting it nullptr because in my print function,I check for nullptr for head node, and ask user to create list first if head-node is nullptr).
void del_list(stud* &orig_head)
{
cout << "Deleting entire list..." << endl;
delete orig_head;
orig_head = nullptr;
}
I have a question regarding the way I choose to delete the list, since im not clearing each node of list, im simply clear the head pointer, what will happen to all the other nodes? Will this approach create a memory leak ?
Edit:
Im not using OOP to implement linked list,im implementing linked list using struct and couple of functions.
I like to handle this problem recursively:
void deleteNode(Node * head)
{
if(head->pNext != NULL)
{
deleteNode(head->pNext)
}
delete head;
}
If we have a list of 5 items:
head->pNext->pNext->pNext->pNext->NULL;
Then, the function will first get called for head, then for each pNext until the last one. When we reach the last one, it will skip deleting the next one (since it's null) and just delete the last pNext. Then return and delete the list from back to front.
This is assuming that each node's pNext is initialized to NULL. Otherwise, you'll never know when you've reached the end of the linked list.
Your code will cause memory leak. To delete it correctly, traverse the list and while traversing delete each node separately. And finally make head pointer to point to NULL value. You can have a look at the following code.
void deleteList(struct Node** head_ref)
{
struct Node* current = *head_ref;
struct Node* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
//Now make head_ref point to null
*head_ref = NULL;
}
The below is meant to reverse a linked list. It seems to work till it gets to the last line. When I debug, both "current" and "result" are of the same type (Node*) and "result" is the list reversed. But when the function completes, current only has the first value of the "result" list. Anyone know why "current" is not the full list when the function completes?
struct Node {
int data;
Node* next;
};
void reverseList(Node** head)
{
Node* current = *head;
Node* result = NULL;
while (current != NULL)
{
Node* temp = current;
current = temp->next;
temp->next = result;
result = temp;
}
current = result;
}
There are multiple problems with the shown logic.
We can start with the obvious observation that the goal of reverseList is, apparently, to reverse a singly-linked list.
The second observation is that the function takes a single parameter, a pointer to the head node, and it returns a void.
From, that we conclude that the function should update the head node, but there's nothing in the code that does that.
Additionally, there's really no reason why this function should take a double pointer like that, a pointer to the head node, and update it. It's much simpler for the function to take an ordinary pointer to the first element of the list, the existing head pointer, and then return the head pointer of the reversed list.
With this simple change, the resulting logic becomes much, much shorter and simpler:
Node *reverseList(Node *head)
{
Node *current=NULL;
while (head)
{
Node *next=head->next;
head->next=current;
current=head;
head=next;
}
return current;
}
That's it.
you need to update the head at the end of your algorithm:
current = result;
*head = current;
I am writing a function to delete the last node in a linked list. This is what I have, and other code I've found online searching for a solution is very similar (I have found several), but when I execute it it creates some sort of infinite loop when deleting the last element of a linked list (it deletes other elements just fine though).
Here is the code I imagine is causing a problem:
void delete_final(Node* head){
if(head == NULL) {
return; }
if(head->next == NULL) {
delete head;
head = NULL;
return;
}
//other code
}
I imagine it's an issue with the memory (particularly after the delete head; statement), but I'm really stuck and would appreciate any help or an explanation for why this doesn't work (I possibly don't have a very good understanding of pointers and memory in C++, I'm just starting with it)
Here is my Node code for reference:
struct Node {
int key;
Node* next;
};
Thanks for any help!
Original code:
void delete_final(Node* head){
if(head == NULL) {
return; }
if(head->next == NULL) {
delete head;
head = NULL;
return;
}
//other code
}
The "other code" is not specified, but if the list has exactly one node then the above code will
delete that first node, and
update the local pointer head, which doesn't update the actual argument since it was passed by value.
As a result the calling code will be left with a dangling pointer in this case, a pointer pointing to a destroyed object, or to where such an object once was. Any use of such a pointer is Undefined Behavior. It might appear to work, or crash, or just silently cause dirty words tattoo to appear on your forehead – anything…
One fix is to pass the first-pointer by reference:
void delete_final(Node*& head){
if(head == nullptr) {
return; }
if(head->next == nullptr) {
delete head;
head = nullptr;
return;
}
//other code
}
A nice helper function for dealing with linked lists, is unlink:
auto unlink( Node*& p )
-> Node*
{
Node* const result = p;
p = p->next;
return result;
}
The implementation is perhaps a bit subtle, but all you need to remember to use it is that it updates the pointer you pass as argument, which should be either a first-node pointer or a next pointer in the list, and returns a pointer to the unlinked node.
So e.g. you can do
delete unlink( p_first );