Crash when deleting nodes in a circular list - c++

I got some problems with the algorithm for "clearing" nodes in a circular list: most of times the program crashes and sometimes not. I'm quite sure that the algorithm is ok and I have no clue about the solution... :-(
Here some piecies of code:
The clear() function (Note: mFreenode is the "head-tail free" node for the circular list):
List* clear() {
if (mFreenode->getNext() != 0) {
Node<T>* current = mFreenode->getNext();
Node<T>* temp = 0;
while (current != mFreenode) {
temp = current->getNext();
delete current;
current = temp;
}
}
mFreenode->setNext(0);
mFreenode->setPrev(0);
mSize = 0;
return this;
}
And this is the Node destructor:
~Node() {
delete &item;
}
Any suggestion?

Your destructor looks very suspicious -- I'm assuming that item is a member variable of Node. If item is a value type (eg int or std::string), then you shouldn't be deleting it at all. If it's a pointer, then perhaps you should be doing delete item; -- but only if the Node has ownership of the item that it has a pointer to.

When you delete item; you do not make the previus Node to point to the Node after the Node you delete. As a result the Node previus to the one you delete points to nowhere.

Please never do the following with a circular linked list:
while (current != mFreenode) {
temp = current->getNext();
delete current;
current = temp;
}
Why do you think it is a circular linked list?? Because the tail node points to the first one, so when you do that the loop will go ahead and delete all nodes except the node before current.
and then you try to access it bad idea:
mFreenode->setNext(0);
mFreenode->setPrev(0);

Related

How to delete from the last node in a linked list to a specific node in that list using recursion

So i am trying to delete from a specific node in a linked list but the problem doesn't come from deleting from the node to end ,it comes from trying to delete from the last node to a specific node while trying to use a recursion.
This is what I currently have (deleting from the node to last node)
void rLL<T> :: recursiveDelete(item<T> * node)
{
if (node != nullptr)
{
item<T> * nodeptr = node -> next;
delete node;
size--;
recursiveDelete(nodeptr);
}
}
Now I have to try and switch it around.And I have no idea how to do that.
This is for a school project so please ,if possible, try to keep it simple.
edit:Let's say the list consist of 1,2,3,4,5,6,7 and node 5 was put in to the parameter node then 7 ,6 ,5 should be deleted in that specific order (to clear things up a bit)
The answer to your question is to simply perform the recursive call before calling delete.
However, even if you were able to delete the specified node without failure, the code you presented would still have a major flaw - it does not update the next field of the node prior to the specified node, so you would end up leaving the list in an invalid state, as that prior node would become the new tail node but have a non-null next pointer that does not terminate the list properly.
For a single-linked list, you would have to iterate from the front of the list in order to discover that prior node to update. But once you reach the specified node, and know its previous node, then you can use a recursive algorithm for the rest of the list, eg:
template<typename T>
void rLL<T>::recursiveDelete(item<T> *node, item<T> *previous)
{
if (!node) return;
recursiveDelete(node->next, node);
if (previous) previous->next = nullptr;
--size;
delete node;
}
void rLL<T>::deleteToEnd(item<T> *startNode)
{
if (!startNode) return;
item<T> *node = head;
item<T> *previous = nullptr;
while (node)
{
if (node == startNode)
{
recursiveDelete(node, previous);
return;
}
previous = node;
node = node->next;
}
}
Live Demo
That being said, a double-linked list is better suited for this task, as you don't need to iterate from the front of the list at all, you can start right at the specified node, eg:
void rLL<T>::deleteToEnd(item<T> *startNode)
{
if (!startNode) return;
deleteToEnd(startNode->next);
item<T> *previous = startNode->previous;
if (previous) previous->next = nullptr;
if (head == startNode) head = nullptr;
tail = previous;
--size;
delete startNode;
}
Live Demo
If I understand this correctly, you want to delete a node that points to your specific node. If I were doing this I would have 2 nodes, currentNode and prevNode. When you iterate forward you move both of them and that way when currentNode meets the specifications, you can delete prevNode. If I don't understand the question right let me know.

c++ link list remove all method is leaving last element unremoved

I have developed a function to remove all nodes from linked list. All nodes are successfully deleted except the last one. Please help me why last node is not being deleted? Following is my code:
void StudentLinkList::removeAll() {
StudentData *traversePointer = this->head;
while (this->head->getNext() != nullptr) {
this->head = this->head->getNext();
delete traversePointer;
traversePointer = this->head;
}
delete this->head;
}
So close
void StudentLinkList::removeAll() {
StudentData *traversePointer;
// Continue while there are any elements on the list
// Extra parens to indicate that we want the result of the
// assignment as boolean. No need to compare to nullptr.
while ( (traversePointer = this->head) ) {
// First preserve the rest of the list
this->head = this->head->getNext();
// only then can we delete this node
delete traversePointer;
}
// list is now empty
}
You're deleting this->head, but you should set this->head to nullptr as well. While you're freeing the memory the node is using, the data stored in the node's old location usually isn't immediately overwritten, which is why it looks like the last node is not deleted.
EDIT: downvote is duly noted, could someone clarify what I got wrong?
Also, I agree with the above comment - you should also check if this->head is null before the loop.

How can I delete a node in my linked list in C++?

I've pasted my work so far here:
http://codepad.org/WhJuujRm
The concepts of linked lists boggle my mind, so I thought I'd practice. I know how to add nodes, and edit nodes, but I don't know how to remove nodes in my particular scenario.
My Pseudo Code:
previous == now - 1;
if(stdid == now->getID());
previous->setNext(now->getNext);
delete now;
return;
How could I implement this?
The mind-tease in deleting an element from a linked list is updating the pointer that brought you to the element in the first place. In your list case, that could be top (and/or possibly bottom), it could be some node's next. As you walk through the list hunting with a cur pointer, keep a prev pointer which you advance one step behind as you enumerate. Assuming you find the victim node (if you don't, there's nothing to do, woot!), prev will be in one of two states:
It will be NULL, in which case top is the pointer that refers to your victim node and top must be updated, or...
It will be some pointer to a node, in which case that node's next member needs to be updated to the reflect the victim node's next member value.
In both cases bottom may need updating as well. In the first case bottom will need to change if the list only had one node and you're deleting it. i.e. you will have an empty list when finished. Easy enough to tell, since top will be NULL after to detach cur and set top equal to cur->next. Even easier for you, since you're keeping a size member in your list container; if it was 1, you know both head and bottom
In the second case, the last node may be the victim node. In that case bottom has to be updated to reflect the new end of the list (which is coincidentally in prev, and may be NULL if, once again, the list had only a single element. How do you tell if the victim was the last node in the list? If it's next member is NULL, it has to be the last node, and bottom must be updated.
So something like this, a delete function based on ID search
void deleteStudent(int id)
{
student *cur = top, *prev = nullptr;
while (cur && cur->getID() != id)
{
prev = cur;
cur = cur->getNext();
}
// found a node?
if (cur)
{
student *pNext = cur->getNext();
// set new next pointer for prev, or new top
if (prev)
prev->setNext(pNext);
else
top = pNext;
// update bottom if needed
if (!pNext)
bottom = prev;
delete cur;
--scnt;
}
}
Other delete options and criteria I leave to you.
Best of luck.
This should work, but I have not tested it.
There is a special case, when the first node is deleted. previous is set to NULL for the first iteration, and the top has to be adjusted in this case.
I didn't use bottom, because it's not the way I would do it. If you use bottom, there is a second special case, when you delete the last student. I would mark the end of the list with a next pointer set to NULL, because this eliminates this special case.
bool deleteStudent(int id)
{
student* now = top;
student* prev = NULL;
while(now != NULL) {
student* next = now->getNext();
if(id == now->getID()) {
delete now;
if(prev) prev->setNext(next);
else top = next;
return true;
}
prev = now;
now = next;
}
return false;
}
I did not use your notation but I think you can get the point.
prev = NULL;
current = top;
while (current != NULL && !isfound(current)){
prev = current;
current = current->next;
}
// current point to the element you want to delete (if not NULL)
if(current != NULL) {
if(previous != NULL) {
previous->next = current->next;
}
else {
top = current->next;
}
delete current;
}

Can't Delete My Temporary Pointers?

I'm having an issue with deleting pointers. I don't think I'm doing anything compiler illegal or anything, but perhaps I am, so I would appreciate it if someone could explain the flaw in my logic. I'm hoping the below function should be enough to help, as the whole thing would be a lot to transcribe, but if any more of the code is required, please let me know and I'll add it!
The below is a function to remove lockers from a linked list I've created. I've done my best to cover every conceivable case. The problem arises when I try to actually deallocate the memory of a locker I want to delete. The lines where I've tried to delete the temp variable that references that locked are commented out, because the code breaks with them included. Obviously, though, without them, I can't delete the lockers like I want.
int SelfStorageList::removeLockersOverdue() {
int lockersDeleted = 0;
if (isEmpty()) {
return 0;
}
if (head->objLocker.isRentOverdue && head==tail) { //If that was the only locker, the tail needs to be updated to = head = 0
delete head;
head = tail = 0;
return ++lockersDeleted;
}
LockerNode *prev = head;
LockerNode *curr = head->next;
while (curr != 0) {
if((curr == tail) && curr->objLocker.isRentOverdue) { //If the current locker is tail and needs deleting
LockerNode *temp = curr;
curr = prev;
//delete temp;
lockersDeleted++;
}
if(prev->objLocker.isRentOverdue) { //General case: Previous locker needs deleting
LockerNode *temp = prev;
prev = prev->next;
curr = curr->next;
//delete temp;
lockersDeleted++;
}
else { //Update the pointers if not updated anywhere else
prev = prev->next;
curr = curr->next;
}
}
return lockersDeleted;
}
Any "pointers"? (Terrible pun. :p )
Because you're maintaining a singly-linked list, I see you're keeping track of a prev pointer as you're iterating through your list. That's as it should be, of course, since you can't get the previous node of a given node in a linked list if it's singly-linked without remembering what its previous node was. Your problem is simply that your logic is busted: If a deletion is needed, you need to be deleting the curr node, and patching up the prev node to point its next pointer to curr->next before you delete curr.
Think about it: What you're doing is deleting the prev node, but there's likely a "more previous than that" node that's still pointing to the prev node that you just deleted. The next time you iterate through the list, you'll be iterating into formerly allocated nodes, which may be allocated for some entirely different purpose by that point. Your memory allocator is failing some internal assertion because likely on the next time you call removeLockersOverdue(), the memory has NOT yet been allocated to something else, and you're still finding the same node there that you already deleted, and finding again that it's overdue, and deleting it again, and your memory allocator is complaining that you're deleting memory that isn't allocated. (It would be really nice if it gave you that clear of a message, wouldn't it!)
Also, your special case stuff for handling the very first node & last node can be simplified & commonized; I'll avoid rewriting it for you so you can see if you can simplify it yourself.
while (curr != 0) {
if((curr == tail) && curr->objLocker.isRentOverdue) {
LockerNode *temp = curr;
curr = prev;
//delete temp;
lockersDeleted++;
}
You are not updating the previous node's next pointer here, so it ends up dangling (pointing to memory that is deleted). You also leave tail pointing at the deleted node.
if(prev->objLocker.isRentOverdue) {
LockerNode *temp = prev;
prev = prev->next;
curr = curr->next;
//delete temp;
lockersDeleted++;
}
Again, you don't update the next pointer in the list that points at the deleted node.
else { //Update the pointers if not updated anywhere else
prev = prev->next;
curr = curr->next;
}
}
I think you are greatly confusing yourself by carrying around two pointers in the loop. Try to write it again with just a single pointer tracking the node you are currently examining, and draw some pictures of the three possible cases (remove first node, remove last node, remove internal node) to ensure you are getting the removal logic right.

How to remove an item from a structure array in C++?

I have the following array structure (linked list):
struct str_pair
{
char ip [50] ;
char uri [50] ;
str_pair *next ;
} ;
str_pair *item;
I know to create a new item, I need to use
item = new str_pair;
However, I need to be able to loop through the array and delete a particular item. I have the looping part sorted. But how do I delete an item from an array of structures?
What you've shown is not an array of struct, but a linked list of struct containing arrays (of type char).
An array of struct would look like this:
str_pair array_of_structs[10];
// or:
str_pair* dynamically_allocated_array_of_structs = new str_pair[10];
If you actually have something like this, you don't need to delete single items from an array. Let's say you've initialized your array as follows:
str_pair* array_of_structs = new str_pair[10];
Then you delete the whole array (including all of its items) using:
delete[] array_of_structs;
Again, you can't delete single items in an array allocated with new[]; you perform a delete[] on the whole array.
If, on the other hand, you intended to say "linked list of struct", then you'd generally delete an item similarly to the following:
str_pair* previous_item = ...;
str_pair* item_to_delete = previous_item->next;
if (item_to_delete != 0)
{
previous_item->next = item_to_delete->next; // make the list "skip" one item
delete item_to_delete; // and delete the skipped item
}
Or, in English: Find the item (A) preceding the item which you want to delete (B), then adjust A's "next" pointer so that B will be skipped in the list, then delete B.
You need to be careful with special cases, i.e. when the item to be removed from the list is the first item or the last one. The above code is not sufficient when you want to delete the first item in the list, because there will be no previous_item. In this case, you'd need to change the pointer to the list's first element to the second element.
Your code:
void deleteitem(char *uri)
{
str_pair *itemtodelete;
curr = head;
while (curr->next != NULL) {
if ((strcmp(curr->uri, uri)) == 0) {
itemtodelete = curr;
curr = itemtodelete->next;
delete itemtodelete;
curr = head;
return;
}
curr = curr->next;
}
}
Some things are wrong here:
If head is null, the test curr->next != NULL will cause a segfault. (You must never dereference a null pointer!)
Your code for removing an item from the list is completely incorrect. Worst of all, you delete a node without changing the previous item's next pointer. The previous item will thus reference an item that's no longer there.
A detail: curr = head; before the return statement doesn't do anything useful at all.
Suggested code:
Do it in two steps: One function to find the node to be deleted via its attached uri, and one function to remove the node. You could separate it even better than the code below does, but it should be a starting point:
str_pair* finditemwithuri(char* uri)
{
str_pair* current = head;
while (current)
{
if (strcmp(current->uri, uri) == 0) return current;
current = current->next;
}
return 0;
}
void deleteitem(char* uri)
{
// find linked list node with that uri; abort if uri not in list
str_pair* itemtodelete = finditemwithuri(uri);
if (!itemtodelete) return;
// special case: node to be deleted is the list's head
if (itemtodelete == head)
{
head = itemtodelete->next;
delete itemtodelete;
return;
}
// else, iterate over list nodes
// up to the one preceding the node to be deleted
str_pair* current = head;
while (current)
{
if (itemtodelete == current->next)
{
current->next = itemtodelete->next;
delete itemtodelete;
return;
}
current = current->next;
}
}
Just use std::list. There's no reason to manually write such a construct.
http://msdn.microsoft.com/en-us/library/802d66bt(VS.80).aspx
std::list offers remove.
You can delete it using the ordinary delete keyword, but that will not shift all other members of the array. If you want this kind of behaviour take a look at std::vector or something like that.
It is maybe off topic, but why dont you use the std::list library ?
As others have pointed out, this is a Linked List, not an array. To answer your question for linked lists:
To insert an item:
str_pair* p = // iterate over the linked list to your insertion point
str_pair* item = new str_pair;
item->next = p->next;
p->next = item;
That inserts a new str_pair after p.
To remove an item:
str_pair* p = // iterate to just before your deletion point
str_pair* item = p->next;
p->next = p->next->next;
delete item;
This will remove the element after p
To do this with your code:
void deleteitem(char *uri)
{
str_pair *previous = NULL;
curr = head;
while (curr != NULL) {
if ((strcmp(curr->uri, uri)) == 0) {
// modify the previous element to skip over our deleted one
if (previous)
previous->next = curr->next;
else
head = curr->next;
// safely delete the element, now that no one points to it
delete curr;
curr = head;
return;
}
// always remember our previous element, so we can fix its 'next' pointer
previous = curr;
curr = curr->next;
}
}
You need a better add method too:
void additem(char *uri, char *ip)
{
curr = head;
// traverse the list until we're at the last item
while (curr->next != NULL) {
curr = curr->next;
}
// attach a new element to the list
curr->next = new str_pair;
// go to that new element
curr = curr->next;
// set the values of the new element
strcpy(curr->ip, ip);
strcpy(curr->uri, uri);
curr->next = NULL;
curr = head;
}