Core Dump when deleting pointer C++ - c++

I am learning C++ and here I am trying to implement the pop() function of a stack. I am confused about when to delete pointers, and how to delete them correctly. The following code causes a core dump error, however I found a few ways to avoid the core dump. The problem is that I point a pointer to another pointer, and I want to delete both. If I set one to null I can delete both, but if I point one to the other I cannot delete both. What is the appropriate course of action here and why can't I delete both when one points to the other? Also, this is not a doubly linked list, and I am not keeping track of the second node from the top so I must traverse the entire list to delete from the top.
I apologize as it seems that this question gets asked often. There are so many discussions that I cannot sort out one that addresses my problem specifically.
int List::pop() {
int result = -1;
if (head != NULL) {
result = curr->data;
nodePtr delPtr;
if (curr == head) {
delPtr = head;
head = NULL;
}
else {
nodePtr previousNode = head;
while(previousNode->next != curr) {
previousNode = previousNode->next;
}
delPtr = curr;
curr = previousNode;
curr->next = NULL;
previousNode = delPtr; //previousNode = NULL;?????
delete previousNode; //unecessary?????
}
delete delPtr; //Have to delete this one no matter what
}
else {
cout << "The stack is empty" << endl;
}
return result;
}//END pop

You are deleting the curr node twice.
Once in these lines:
previousNode = delPtr; //previousNode = NULL;?????
delete previousNode; //unecessary?????
and once in the line:
delete delPtr; //Have to delete this one no matter what
You can remove the first two lines.

You can remove both these lines:
previousNode = delPtr; //previousNode = NULL;?????
delete previousNode; //unecessary?????
And it will work and be correct.
The error is from deleting the same pointer twice.
previousNode = delPtr is just making a copy of the pointer, there is still only one object.

You don't need to delete twice, you are only removing one item.
Just because a pointer points to something doesn't mean you have to delete it if you change the pointer or it goes out of scope.
In general, you need to match up deletes with news.
In short, you can remove both your commented lines as you already have delPtr set up for deleting.

int List::pop()
{
int result = -1;
if (head != NULL)
{
nodePtr prev = head;
nodePtr curr = head;
while (curr->next != NULL)
{
prev = curr;
curr = curr->next;
}
result = curr->data;
if (head == curr)
{
head = NULL;
}
else
{
prev->next = NULL;
}
delete curr;
}
else
{
cout << "The stack is empty" << endl;
}
return result;
}//END pop

Related

Read access violation while deleting multiple nodes from a linked list

I need to implement a doubly linked list in c++ for a small animation running on console. The linkedlist stores clouds and then they move through the console and as each cloud hits the end of screen, it needs to be deleted from linked list. As the cloud hits the end, it has a variable called alive which is set to false so it can be deleted.
I can't upload the full game code, but I have recreated the problem in dummy code by creating sample clouds where some of them have alive = true and alive = false. I have also updated the previous and next nodes of the cloud to be deleted but I still get an error:
Exception thrown: read access violation. temp was 0xFFFFFFFFFFFFFFFF.
Code below (include statements removed for simplicity)
Test.cpp
int main() {
Cloud* a = new Cloud('a');
a->alive = false;
Node* a1 = new Node(a);
Cloud* b = new Cloud('b');
b->alive = false;
Node* b1 = new Node(b);
LinkedList list;
list.Insert(a);
list.Insert(b);
Node* temp = list.head;
while (temp != nullptr) {
if (temp->data->alive == false) list.Delete(temp); // throws exception after deleting a single node.
temp = temp->next;
}
return 0;
}
LinkedList.cpp delete function
void LinkedList::Delete(Node* del) {
if (del == head) {
OutputDebugStringA("Cloud in head");
Node* temp = head;
head = head->next;
head->prev = nullptr;
delete temp;
return;
}
else {
Node* temp = head;
while (temp != tail->next) {
if (temp == del) {
if (temp->next != nullptr) {
OutputDebugStringA("Cloud in mid");
temp->prev->next = temp->next;
temp->next->prev = temp->prev;
break;
}
else {
OutputDebugStringA("cloud at tail");
tail = temp->prev;
tail->next = nullptr;
break;
}
}
temp = temp->next;
}
delete temp;
temp = nullptr;
}
}
Node.cpp
#include "Node.h"
#include <iostream>
using namespace std;
Node::Node() {
this->data = nullptr;
}
Node::Node(Cloud* data) {
this->data = data;
}
Someone please point out where am I going wrong. Thanks
if (temp->data->alive == false) list.Delete(temp); // throws exception after deleting a single node.
temp = temp->next;
Here, temp gets passed into the Delete() method. Afterwards temp gets set to temp->next.
In Delete():
delete temp;
temp = nullptr;
The object referenced by the passed-in temp pointer (here, this temp, by the virtue of the preceding logic, is the same pointer that gets passed in) gets deleted.
After returning, temp->next references a deleted object.
This is at least one confirmed instance of undefined behavior in the shown code. This may or may not be the only bug.
As it's been pointed out to you in comments, this overall Delete() logic is fundamentally flawed. It should not involve any kind of iteration, for a doubly-linked list. You will end up fixing this bug while rewriting Delete() from scratch (which includes rethinking how Delete() itself gets called, because after it returns temp is no longer usable for anything).
As #John Zwinck and #Sam Varshavchik pointed out that the implementation of delete method was flawed and temp became useless after the Delete function returned.
I fixed it by using another temp pointer and fixing the delete method to be O(1).
Delete Method
void LinkedList::Delete(Node* del) {
if (del == head) {
head = head->next;
head->prev = nullptr;
}
else if (del == tail) {
tail = del->prev;
tail->next = nullptr;
}
else {
del->prev->next = del->next;
del->next->prev = del->prev;
}
delete del;
}
Node deletion
Node* temp = cloud_list.head;
Node* next;
while (temp != nullptr) {
next = temp->next;
if (temp->data->alive == false) {
cloud_list.Delete(temp);
}
temp = next;
}
The deletion now works fine.

Deleting node in linked list causes output of seemingly random nubmers

I am trying to delete a node from a linked list using this function:
void del_node(int del_data)
{
node* temp = NULL;
node* trail = NULL;
node* del_ptr = NULL;
temp = head;
trail = head;
while (temp != NULL && temp->data != del_data)
{
trail = temp;
temp = temp->next;
}
if (temp != NULL) {
del_ptr = temp;
temp = temp->next;
trail->next = temp;
delete(del_ptr);
}
}
It seems like it deletes it fine until i print the linked list using this:
void print()
{
node* temp = NULL;
temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
and it starts outputting seemingly random numbers, can anybody help me with this, really confused as this code comes from a tutorial.
Your algorithm doesn't manage the head pointer correctly whatsoever. Any changes that ultimately should modify the head pointer don't, and that's a huge problem. A pointer to pointer algorithm not only solves this problem, it also delivers a considerably more succinct solution:
void del_node(int del_data)
{
struct node **pp = &head;
while (*pp && (*pp)->data != del_data)
pp = &(*pp)->next;
if (*pp)
{
node *tmp = *pp;
*pp = tmp->next;
delete tmp;
}
}
This will work for any list condition including:
An empty list. i.e. head is null.
A single-node list. If the value matches head->data it will properly delete and reset the node pointer.
A multi-node list. The first matching node will be removed, and it will properly fix up the head node pointer if that was the matching location.
All of the above, in cases where there is no matching node, the list remains unchanged.
Fulfilling all of that in such a short algorithm + implementation is beneficial.
I'll comment on your code inline:
void del_node(int del_data)
{
node* temp = NULL;
node* trail = NULL;
node* del_ptr = NULL;
temp = head;
trail = head;
// This is fine, but recommend you use nullptr instead of NULL.
// This will find the first instance of data matches del_data,
// But if you are trying to delete all instances of del_data,
// You'll need to do this a little differently.
while (temp != NULL && temp->data != del_data)
{
trail = temp;
temp = temp->next;
}
// This if is fine, but see previous comment about using nullptr
// instead of NULL.
if (temp != NULL) {
del_ptr = temp;
temp = temp->next;
// Problematic: What if trail is null?
trail->next = temp;
delete(del_ptr);
}
}
Your code isn't bad. I wouldn't have written exactly like this, but I'm going to replace your if-statement:
if (temp != nullptr) {
// If trail is nullptr, then we're deleting from the head
if (trail == nullptr) {
head = temp->next;
}
else {
trail->next = temp->next;
}
delete(temp);
}
There's no need for the temporary. Just point around temp as you see in the if-else block and then delete temp.

Implementing "deleting algorithm" for linked list type data structures

Here is a delete function I have written to delete some nodes from my linked list when needed.
the linked list is stored as alphabetically ordered
Using below function, when I try to delete the very first element of a linked list (named head), I get an runtime error when I am trying to print the linked list (using the print function) and the program crashes. I am aware that this is probably caused by not creating a new head node. But I do not know how to solve this. This is probably very simple but couldn't figure out. Can you please help :)
this is the delete function:
void deleteName(someStruct * &head, string name)
{
someStruct * ptr = head;
someStruct * previous;
if(head == NULL)
{
cout << "empty";
}
else if(head->name == name)
{
ptr = head;
head = head->next;
delete head;
}
else
{
while (ptr -> name != name)
{
previous = ptr;
ptr = ptr->next;
}
previous->next = ptr->next;
delete ptr;
}
}
this is the print function:
void Print(someStruct * head)
{
someStruct * pointer = head;
//List is empty
if(head == NULL)
{
cout << "List is empty" << endl;
}
else
{
while(pointer != NULL)
{
cout << pointer->name;
cout << pointer->points << endl;
pointer = pointer->next;
}
}
}
else if(head->name == name)
{
ptr = head;
head = head->next;
delete head;
}
This:
saves the old value of head to ptr, which is correct
advances the inout param head, which is also correct
completely ignores ptr, which contains the old node you want to delete, and instead deletes the current list head, leaving the inout param head pointing to a deleted node.
This bit isn't correct.
Just change delete head to delete ptr.
Note for future reference: the good way to structure this is to use a local sentinel node which doesn't need to be deleted. This removes your special case for head (by adding the invariant that your temporary head can never be removed) and simplifies the code.
void deleteName(someStruct * &head, string name)
{
if(!head) {
cout << "empty";
return;
}
someStruct tmphead;
tmphead.next = head;
for (someStruct *prev = &tmphead; prev->next; prev = prev->next) {
if (prev->next->name == name) {
auto todelete = prev->next;
prev->next = todelete->next;
delete todelete;
// if there can be only one match, just bail out
break;
// otherwise, if there can be many, go round again
// but remember to check whether prev->next is null
// if (!prev->next) break;
}
}
head = tmphead.next;
}
If your someStruct is too large or complex to use a temporary head like this, you can do the same with a temporary local head pointer, and make prev a pointer-to-pointer.
The delete head in else if block is the problem.
Change the block to this :
else if(head->name == name) {
//ptr = head; You don't have to. You already have initialized ptr with head
head = head->next;
delete ptr; //Delete prt not head, head is now the next node which you assigned in previous line
}
else if(head->name == name){
ptr = head;
head = head -> next;
delete ptr; // change to this statement n you're good to go
}

Deletion in a linked list

Qn) Given only a pointer to a node to be deleted in a singly linked list, how do
you delete it?
I am trying to delete the last element i.e., 1 but the else part goes into an infinite
loop printing garbage values.
Original link.
int main()
{
struct Node* head = NULL;
push(&head, 1);
push(&head, 4);
push(&head, 6);
push(&head, 8);
print(head);
del_p(head->next->next->next);
cout << endl;
print(head);
return 0;
}
void del_p(struct Node* current)
{
struct Node* temp;
if (current->next != NULL)
{
temp = current->next;
current->data = temp->data;
current->next = temp->next;
free(temp);
}
else
{
free(current);
current = NULL;
}
}
The else branch of your function tries to reassign current to NULL. This is problematic because current is a local copy of the pointer passed in. That is, you can't modify the value of the original pointer.
This is why you are receiving garbage, because you're accessing a node whose memory has already been deallocated.
You either need a double pointer, or preferably a reference to the node:
void del_p(struct Node*& current)
If you pass in the node to be deleted and the head node then you can loop until you find the node prior to the node to be deleted. You then need to point the prior node to the node that is pointed to by the node to be deleted and then you can free the node you want to delete.
void delete(struct Node* to_delete, struct Node* head)
{
// check if node to be deleted is the head
if (to_delete == head)
{
head = to_delete->next;
return;
}
// make a local copy of the head just in case as to not alter it
struct Node* tempHead = head;
while(tempHead->next != to_delete)
{
tempHead = tempHead->next;
}
tempHead->next = to_delete->next;
free(to_delete);
}
Just as a disclaimer I haven't tested this code, but conceptually it should work.
The typical algorithm for deleting a node on a linked list would follow the next steps:
Get a temp pointer started in Head.
Move your temp to the node you want to delete (in this case one before the last: temp->next == NULL).
Free the memory for temp2.
Set the pointer of temp->next to NULL.
Return the pointer to head.
Now this is not the only algorithm, there are a lot of ways you can accomplish this. The following code would be my solution to the function del_p (if you would want to delete the last node):
void del_p(struct Node *head)
{
if (head != NULL)
{
struct Node *temp = head;
while (temp->next != NULL) temp = temp->next;
free(temp);
}
}
You can make this code a little more general to make it possible to delete any Node, by passing a pointer to that node (or a value), the code would look as follows:
void del_p(struct Node **head, struct Node *delete_node)
{
if (head != NULL)
{
struct Node *temp = *head;
if (temp == delete_node)
{
*head = (*head)->next;
free(temp);
}
else
{
while (temp->next != NULL && temp->next != delete_node)
temp = temp->next;
if (temp->next != NULL && delete_node != NULL)
{
temp->next = delete_node->next;
free(delete_node);
}
}
}
}
Hope this works for you, this code isn't tested, but tell me if you have troubles!

Sorting a Singly Linked List With Pointers

I am trying to sort a singly linked list using bubble sort by manipulating ONLY the pointers, no keys.
The following gets stuck in the for loop and loops infinitely. I don't understand why this is. Can anybody explain to me why the end of the list is not being found?
Node* sort_list(Node* head)
{
Node * temp;
Node * curr;
for(bool didSwap = true; didSwap; ) {
didSwap = false;
for(curr = head; curr->next != NULL; curr = curr->next) {
if(curr->key > curr->next->key) {
temp = curr;
curr = curr->next;
curr->next = temp;
didSwap = true;
}
cout << curr->next->key << endl;
}
}
return head;
}
If I change the code so that the keys (data) are swapped, then the function works properly but for some reason I am not able make it work by manipulating only pointers.
Logical Error, you are creating an infinite loop with following code -
temp = curr;
curr = curr->next;
curr->next = temp;
I,e next_of_current is pointing to current, so curr->next will always be curr and never will be NULL;
Next you should use previous pointer to fix your list because your list can be traversed in a single direction. So, Think -
If A->B->C->NULL; and you make C and B swap then the new list will still point to A->B and next iteration will be wrong ... because you are not modifying your previous next.
So, another implementation may be -
Node* sort_list(Node* head) {
Node * curr;
Node * prev;
for(bool didSwap = true; didSwap; ) {
didSwap = false;
prev = head;
for(curr = head; curr->next != NULL; curr = curr->next) {
if(curr->key > curr->next->key) {
if (head == curr) {
head = curr->next;
curr->next = head->next;
head->next = curr;
prev = head;
} else {
prev->next = curr->next;
curr->next = prev->next->next;
prev->next->next = curr
}
didSwap = true;
} else if (head != curr) {
prev = prev->next;
}
//cout << curr->next->key << endl; // <- this may cause crash if curr->next now points to NULL; (i,e last element)
}
}
return head;
}
Hope this helps, regards.
You have following problem:
Let you have list with three members: ptr1->ptr2->ptr3. Before swap you have following pointer set: curr=ptr1; curr->next=ptr2; curr->next->next=ptr3. When you perform swap you receive curr=ptr2; curr->next=ptr1; curr->next->next=ptr2.
E.g. you lost ptr3. You need to change code of inner loop with following:
temp = curr;
temp->next = curr->next->next; // Save ptr3
curr = curr->next;
curr->next = temp;
didSwap = true;
The field you want to swap is the value. However, if you swap the node, the next field will change, the question becomes a little more complex, you need keep the next field right. In a word, change value is a simple and good method.
node *sorted_list(node *head) {
node *index1,*index2;
for(index1=head;index1->next!=NULL;index1=index1->next) {
for(index2=index1->next;index2!=NULL;index2=index2->next) {
if(index1->data>index2->data) {
int temp=index1->data;
index1->data=index2->data;
index2->data=temp;
}
}
}
return head;
}