Destructor for circular linked list in c++? - c++

when the destructor of 'class LL' ~LL() gets called for this circular singly linked-list, the program crashes instead of freeing up the heap space of the pointer. How can I solve this problem?
class Node {
public:
int data;
Node *next;
};
class LL {
private:
Node *head, *tail;
public:
LL() {
head = NULL;
tail = NULL;
}
// destructor
~LL() {
Node *p = head;
while (p->next != head) {
p = p->next;
}
while (p != head) {
p->next = head->next;
delete head;
head = p->next;
}
if (p == head) {
delete head;
head = nullptr;
}
}
// circular singly Linked list
void createLL() {
int n, x;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x;
Node *t = new Node;
t->data = x;
t->next = NULL;
if (head == NULL) {
head = tail = t;
} else {
tail->next = t;
tail = t;
}
}
tail->next = head;
}

There are a few issues with the linked list.
The linked list's destructor assumes that head isn't null, when there is a possibility that it could be. Make sure to check that head isn't null before trying to clean up memory. Once that is done, it looks like your original destructor should work.
The function createLL will invoke undefined behavior if the user enters a size less than or equal to 0.
Specifically this line tail->next = head;
TreateLL is a misnomer as it doesn't actually 'create' a new list in the expected sense. The contents aren't cleared, and thus n elements are appended to the end of the current list.
Also, a circularly linked list can be created with just a single tail pointer.
However, getting your implementation of a circular linked list to work looks like this
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* next;
};
class LL {
private:
Node* head, * tail;
public:
LL() : head(nullptr),
tail(nullptr) {
}
~LL() {
if (head) {
Node* p = tail;
while (p != head) {
p->next = head->next;
delete head;
head = p->next;
}
if (p == head) {
delete head;
head = nullptr;
}
}
}
void storeUserInput() {
int n, x;
cin >> n;
if (n <= 0) {
return; //no input to retrieve.
}
for (int i = 0; i < n; i++) {
cin >> x;
Node* t = new Node;
t->data = x;
t->next = nullptr;
if (head == nullptr) {
head = tail = t;
}
else {
tail->next = t;
tail = t;
}
}
tail->next = head;
}
};
int main() {
LL l;
l.storeUserInput();
char response;
std::cin >> response;
}
It seems that you have access C++ 11 or above compiler, if so then you should be using nullptr in place of NULL as it is a definitive pointer type. See more here

You can do it in two steps:
Make the list non-circular. This has two sub-steps:
Detect the loop. There are published algorithms to do this. Edit: Your list has a tail pointer, so there is no need to search for it in your case.
Point the back referencing node to null (or sentinel)
Delete the list which is now non-circular in a loop. This is trivial.

While trying to delete in a loop your circular reference will lead to deleted memory and will have undefined behavior. So first consider breaking the circulatiry:
tail->next = 0;
Then delete in a loop
Node* p = head;
while(p)
{
Node* temp = p;
p = p->next;
delete temp;
}
By the way. tail->next will always point to the head. So you always will have both, the head and the tail in the same pointer. So you can clean the memory like this:
Node* p = tail->next; //this is head
tail->next = 0;
while(p)
{
Node* temp = p;
p = p->next;
delete temp;
}

Related

C++: potential memory leak in linked list

I'm writing a class of linked list, I feel that for the member function that used to delete specific element might cause the memory leak. The code is below.
struct node
{
int data;
node *next;
};
class linked_list
{
private:
node *head,*tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node *tmp = new node;
tmp->data = n;
tmp->next = NULL;
if(head == NULL)
{
head = tmp;
tail = tmp;
}
else
{
tail->next = tmp;
tail = tail->next;
}
}
void DelElem(int locat)
{
int j{1};
node* tmp = new node;
if (locat == 1)
{
tmp = head->next;
head = tmp;
delete tmp;
}
else
{
node* n = head;
while (j < locat - 1)
{
n = n->next;
j++;
}
tmp = n->next;
n->next = tmp->next;
delete tmp;
}
}
For function 'DelElem', I firstly created a pointer tmp by new operator. However, I assign different address for it which means I lost the original one at the initialization.
How can I fix this problem?
There are few issues with your instance of code, I have corrected that:-
As pointed by others, you are not required to use `new` keyword to declare a pointer.
When one tries to delete the first node of the linked list, then according to your code, it will delete the second node, because of the following
tmp = head->next;
head = tmp;
delete tmp;
Here, tmp is initially pointing to second node,because head->next refers to 2nd node. So instead of that, it should have been like this:-
tmp = head;
head = head->next;
delete tmp;
Now, tmp will point to 1st node, in second line, head will point to 2nd node, and then the first node, pointed by tmp gets deleted.
Here is the corrected version of code:-
struct node {
int data;
node* next;
};
class linked_list {
private:
node *head, *tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node* tmp = new node;
tmp->data = n;
tmp->next = NULL;
if (head == NULL) {
head = tmp;
tail = tmp;
}
else {
tail->next = tmp;
tail = tail->next;
}
}
void DelElem(int locat)
{
int j{ 1 };
node* tmp;
if (locat == 1) {
tmp = head;
head = head->next;
delete tmp;
}
else {
node* n = head;
while (j < (locat - 1)) {
n = n->next;
j++;
}
tmp = n->next;
n->next = tmp->next;
cout << tmp->data;
delete tmp;
}
}
};

How do I properly deallocate memory for a merged LL in the destructor function in c++?

I've created a link list class with some operations.
I am trying to merge two linked lists together, as shown in the main function. I am able to successfully do that operation and have it display on the screen.
I suspect I may be doing something wrong, though, with implementing the tail node's next pointer. When the destructor is called, I turn on the debugger to see what is going on exactly. It deletes all of the nodes successfully and shows that old->next and subsequently head do end up equaling nullptr. I made sure for the destructor to only loop when the empty operation is false for nullptr.
But, for some reason, the destructor continues looping and the program gives me the error:
LinkedList(2000,0x1000d3dc0) malloc: error for object 0x1007239d0: pointer being freed was not allocated
I know the solution may be obvious, but I am completely pooped. The destructor works fine for non-merged lists.
class Node{
public:
int data;
Node* next;
friend class LinkedList;
};
class LinkedList{
public:
Node* head;
public:
LinkedList()
{head = nullptr;}
~LinkedList()
{while (!empty()) remove();}
void addDataBack(int data);
void display();
void remove();
bool empty() const
{return head == nullptr;}
void merge(Node* list1, Node* list2);
};
void LinkedList::addDataBack(int data){
Node *p = new Node;
Node *t;
t = head;
p->data = data;
p->next = nullptr;
if (!head){
head = p;
}
else{
t = head;
while(t->next){
t = t->next;
}
t->next = p;
}
}
void LinkedList::display(){
Node *t = head;
while (t){
cout << t->data << endl;
t = t->next;
}
}
void LinkedList::remove(){
Node *old = head;
head = old->next;
delete old;
}
void LinkedList::insertNode(int index, int data){
Node *node = new Node;
int i = 0;
Node *t = head;
Node *p = nullptr;
node->data= data;
while ( t!= NULL){
if (index == i){
p->next = node;
node->next = t;
break;
}
p = t;
t = t->next;
i++;
}
}
void LinkedList:: merge(Node *list1, Node *list2){
Node* t = list1;
head = list1;
while (t->next) {
t = t->next;
}
t->next = list2;
}
int main(int argc, const char * argv[]) {
LinkedList list;
LinkedList list2;
list.addDataBack(8);
list.addDataBack(3);
list.addDataBack(7);
list.addDataBack(12);
list.addDataBack(9);
list.insertNode(2, 25);
list2.addDataBack(4);
list2.addDataBack(10);
LinkedList list3;
list3.merge (list.head, list2.head);
list.display();
return 0;
}
The code does not compile because you're missing the insert function prototype in the class definition.
See the insertNode function; in the line p->next = node, if index
is 0, then this line is going to indirect a null pointer and throw an exception.
The insertNode function will leak memory if you provide an index outside the current number of nodes - 1
The insertNode function will leak memory if the current list is empty
Here is how it should look.
void LinkedList::insertNode(int index, int data)
{
Node* newNode = new Node;
newNode->data = data;
//Wrap this up quick if the list is already empty.
if (head == nullptr)
{
head = newNode;
return;
}
int i = 0;
Node* current = head;
Node* prev = nullptr;
while (current != nullptr)
{
if (index == i)
{
newNode->next = current;
if (prev)
prev->next = newNode;
return;
}
prev = current;
current = current->next;
i++;
}
//if (index >= i)
//Either delete the new node, or throw an out of bounds exception.
//Otherwise this will result in a memory leak. Personally, I think
//throwing the exception is correct.
delete newNode;
}
Here is the main issue:
Your merge function is a bit confusing, because you are essentially creating a new list from two lists, but not via a constructor, but simply merging them. This will mean that list1 is functionally equivalent to list3, but the addresses are all intermingled. This means that when we exit the main function scope, you will be deleting memory from list1, and then when it destroys list2 it will ALSO delete them again, and list3 will do the same (though it will have crashed before then).
Why not simply make it take one list and then merge the two?
#include <iostream>
#include <string>
using namespace std;
class Node{
public:
int data;
Node* next;
friend class LinkedList;
};
class LinkedList{
public:
Node* head;
public:
LinkedList()
{head = nullptr;}
~LinkedList();
void addDataBack(int data);
void display();
void remove();
void insertNode(int index, int data);
bool empty() const
{return head == nullptr;}
void merge(LinkedList& otherList);
};
LinkedList::~LinkedList()
{
while (!empty())
remove();
}
void LinkedList::addDataBack(int data){
Node *p = new Node;
Node *t;
t = head;
p->data = data;
p->next = nullptr;
if (!head){
head = p;
}
else{
t = head;
while(t->next){
t = t->next;
}
t->next = p;
}
}
void LinkedList::display(){
Node *t = head;
while (t){
cout << t->data << endl;
t = t->next;
}
}
void LinkedList::remove(){
Node *old = head;
head = old->next;
delete old;
old = nullptr;
}
void LinkedList::insertNode(int index, int data)
{
Node* newNode = new Node;
newNode->data = data;
//Wrap this up quick if the list is already empty.
if (head == nullptr)
{
head = newNode;
return;
}
int i = 0;
Node* current = head;
Node* prev = nullptr;
while (current != nullptr)
{
if (index == i)
{
newNode->next = current;
if (prev)
prev->next = newNode;
return;
}
prev = current;
current = current->next;
i++;
}
//if (index >= i)
//Either delete the new node, or throw an out of bounds exception.
//Otherwise this will result in a memory leak. Personally, I think
//throwing the exception is correct.
delete newNode;
}
void LinkedList:: merge(LinkedList& otherList){
Node* thisTail = head;
while (thisTail->next) {
thisTail = thisTail->next;
}
thisTail->next = otherList.head;
otherList.head = nullptr;
}
int main(int argc, const char * argv[]) {
LinkedList list;
LinkedList list2;
list.addDataBack(8);
list.addDataBack(3);
list.addDataBack(7);
list.addDataBack(12);
list.addDataBack(9);
list.insertNode(2, 25);
list2.addDataBack(4);
list2.addDataBack(10);
list.merge(list2);
list.display();
list2.display();
cout << "list2 is " << (list2.empty() ? "empty." : "not empty");
return 0;
}
Final Note:
Try to avoid single letter variables unless they are used for iteration, otherwise (especially with linked lists and pointer juggling) it is very difficult to maintain, debug and receive help for.
But, for some reason, the destructor continues looping and [...]
I doubt that, but this is what might appear to be happening if you are not watching closely enough (in particular, watching the value of the this pointer). It looks to me as though the destructor of list3 will finish looping, at which point the destructor of list2 will start (destroying in the opposite order of construction). If you miss seeing this transition, it could very well look like the destructor is continuing when it is in fact being called a second time.
Since you never changed list2.head, it is still pointing at one of the nodes that had been merged into list3. When list2's destructor starts, head is still pointing at one of the nodes that had just been deleted by list3's destructor. Trying to delete that already-deleted node is an error.

Single pointer for linked list deletion function // is it possible

Currently, I am studying the linked list structure.
As I searched, linked list deletion function utilizing 'double pointer'.
In below code, the node is successfully deleted by double pointer in delete function.
#include <iostream>
using namespace std;
struct node
{
int data;
node* next;
};
class LinkedList
{
private:
node* head;
node* tail;
public:
LinkedList()
{
head = nullptr;
tail = nullptr;
}
void add_node(int n)
{
node* temp = new node;
temp->data = n;
temp->next = nullptr;
if(head == nullptr)
{
head = temp;
tail = temp;
}
else
{
tail->next = temp;
tail = tail->next;
}
}
node* gethead()
{
return head;
}
void display(node * head)
{
if(head == nullptr)
{
cout << "nullptr : No data" << endl;
return;
}
else
{
node* temp;
temp = head;
while(temp != nullptr)
{
cout << temp->data << endl;
temp = temp->next;
}
}
}
void del(node* head, int value)
{
if(!head)
{
return;
}
else
{
node** nd = &head;
while(*nd && (*nd)->data != value)
nd = &(*nd)->next;
if(*nd)
{
node* temp = *nd;
*nd = (*nd)->next;
delete temp;
}
else
{
cout << "No matching data in the node" <<endl;
}
}
}
};
int main()
{
LinkedList la;
la.add_node(10);
la.add_node(20);
la.add_node(30);
la.add_node(40);
la.add_node(50);
la.display(la.gethead()); //10 20 30 40 50
la.del(la.gethead(), 40);
la.display(la.gethead()); //10 20 30 50
return 0;
}
I just want to know why the below code is not working.
I am trying to simplify the code by not using a double-pointer.
#include <iostream>
using namespace std;
struct node
{
int data;
node* next;
};
class LinkedList
{
private:
node* head;
node* tail;
public:
LinkedList()
{
head = nullptr;
tail = nullptr;
}
void add_node(int n)
{
node* temp = new node;
temp->data = n;
temp->next = nullptr;
if(head == nullptr)
{
head = temp;
tail = temp;
}
else
{
tail->next = temp;
tail = tail->next;
}
}
node* gethead()
{
return head;
}
void display(node * head)
{
if(head == nullptr)
{
cout << "nullptr : No data" << endl;
return;
}
else
{
node* temp;
temp = head;
while(temp != nullptr)
{
cout << temp->data << endl;
temp = temp->next;
}
}
}
void del(node* head, int value)
{
if(!head)
{
return;
}
else
{
node* pp = head;
while((pp)->data != value)
pp = pp->next;
if(pp)
{
node* temp = pp;
pp = pp->next;
delete temp;
}
else
{
cout << "No matching data in the node" <<endl;
}
}
}
};
int main()
{
LinkedList la;
la.add_node(10);
la.add_node(20);
la.add_node(30);
la.add_node(40);
la.add_node(50);
la.display(la.gethead()); //10 20 30 40 50
la.del(la.gethead(), 40);
la.display(la.gethead()); //10 20 30 50
return 0;
}
Could you please give me advice about why the above code does not delete the node like the first code?
I think that the second code has to be worked because it deletes the node by utilizing pointer(which saves the address of the node).
Thanks in advance.
First of all, the term is "Pointer to pointer" and not "double pointer". Double pointer is a pointer to a variable of type double.
You should really realize that pointers are simply addresses in your memory.
When you are copying pointer (i.e.: node* pp = head;), you put the address that head points to in pp.
What it means? that both pp and head are pointing to the same address.
But, it is also important to remember that pp and head are variables, and thus are written in the memory as well. Saying that - pp and head also have addresses, but since pp and head are distinct variables, they have distinct addresses.
So the problem comes when you are trying to modify the content of head.
On the first occurence:
node** nd = &head;
while(*nd && (*nd)->data != value)
nd = &(*nd)->next;
You don't modify the content of head (or *nd) at all. And thus, you could used the version with pp.
You problem is with this piece of code:
pp = pp->next;
Here, pp is a copy of the address of the original linked list item, and since it is only a copy, then pp = pp->next does practicly nothing. In this case, you really should have written *nd = *nd->next, because this way change the original value and not a copy you created.
Note: even if you will change in your second example the variable pp to be a pointer-to-pointer, you code will still not be able to delete the first element in the list, since it is passed as a regular pointer to head, and thus only your first version is valid.

How do I make my Linked List Print backwards in C++

How do I make my program print the Linked List backwards? I got the printForward function working fine but the printBackwards function just doesn't seem to do anything. I think I'm on the right track but I'm a little stuck right now. I think the while loop isn't running because temp is NULL for some reason.
Any help would be great.
Thanks
List.h
#include <iostream>
using namespace std;
class LinkedList
{
private:
struct Node
{
int data;
Node * next;
Node * prev;
};
Node * head, *tail;
public:
LinkedList();
bool addAtBeginning(int val);
bool remove(int val);
void printForward() const;
void printBackward() const;
};
#endif
List.cpp
#include "List.h"
LinkedList::LinkedList()
{
head = NULL;
tail = NULL;
}
bool LinkedList::addAtBeginning(int val)
{
Node* temp;
temp = new Node;
temp->data = val;
temp->next = head;
head = temp;
return false;
}
bool LinkedList::remove(int val)
{
return false;
}
void LinkedList::printForward() const
{
Node* temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
void LinkedList::printBackward() const
{
Node* temp = tail;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->prev;
}
cout << endl;
}
app.cpp
#include "list.h"
int main()
{
LinkedList aList;
aList.addAtBeginning(3);
aList.addAtBeginning(10);
aList.addAtBeginning(1);
aList.addAtBeginning(7);
aList.addAtBeginning(9);
aList.addAtBeginning(12);
aList.printForward();
aList.printBackward();
system("pause");
return 0;
}
I find it a bit odd that you only have an addAtBeginning method, and no method to add at the end, the latter which I would consider to be normal use of a linked list. That being said, I think the immediate problem here is that you never assign the tail to anything. Try this version of addAtBeginning:
bool LinkedList::addAtBeginning(int val)
{
Node* temp;
temp = new Node;
temp->data = val;
temp->next = head;
if (head != NULL)
{
head->prev = temp;
}
if (head == NULL)
{
tail = temp;
}
head = temp;
return false;
`}
The logic here is that for the first addition to an empty list, we assign the head and tail to the initial node. Then, in subsequent additions, we add a new element to the head of the list, and then assign both the next and prev pointers, to link the new node in both directions. This should allow you to iterate the list backwards, starting with the tail.
Update addAtBeginning function with given:
bool LinkedList::addAtBeginning(int val)
{
Node* temp;
temp = new Node;
temp->data = val;
temp->prev = temp->next = NULL;
// If adding first node, then head is NULL.
// Then, set Head and Tail to this new added node
if(head == NULL){
// If this linked list is circular
temp->next = temp->prev = temp;
head = tail = temp;
}else{ // If we already have at least one node in the list
// If this linked list is circular
temp->prev = head->prev;
temp->next = head;
head->prev = temp;
head = temp;
}
return false;
}
But remember, if you copy this function with the parts that it makes this list circular, you will get an infinite loop. So, either change print function or dont copy that parts.

stack using linked list

I got "segmentation error" in my code. what is wrong? thanks in advance. p.s it's a stack using linked list.
#include <iostream>
//stack using linked list
class LinkedList {
public:
LinkedList() : head(0), tail(0) {}
~LinkedList() {
while (!empty()) pop();
delete head;
}
void pop() {
node* temp;
temp = head;
for ( ; temp->next_ != tail; temp = temp->next_) {
tail = temp;
}
delete temp;
tail->next_ = 0;
} //removes, but does not return, the top element
int top() {
return tail->value_;
} //returns, but does not remove, the top element
bool empty() {
return head == 0;
}
void push(const int& value) {
node* element = new node(value);
if (empty()) {
head = tail = element;
} else {
tail->next_ = element;
tail = element;
}
} //place a new top element
private:
class node {
public:
node(const int& input) : value_(input), next_(0) {};
int value_; //store value
node* next_; //link to the next element
};
node* head;
node* tail;
};
int main() {
LinkedList list;
list.push(1);
list.push(2);
list.push(3);
list.pop();
std::cout << list.top() << std::endl;
return 0;
}
This part doesn't look right
for ( ; temp->next_ != tail; temp = temp->next_) {
tail = temp;
}
because once you set tail to be the same as temp, temp->next != tail will always be true.
for ( ; temp->next_ != tail; temp = temp->next_) {
tail = temp;
}
The condition should have been
temp->next_ != 0
This method
void pop() {
node* temp;
temp = head;
for ( ; temp->next_ != tail; temp = temp->next_) {
tail = temp;
}
delete temp;
tail->next_ = 0;
} //removes, but does not return, the top element
must be like this:
void pop() {
if( head == tail )
{
delete head;
head = 0;
}
else
{
node* temp;
temp = head;
for ( ; temp->next_ != tail; temp = temp->next_) {
}
delete tail;
temp->next_ = 0;
tail = temp;
}
} //removes, but does not return, the top element
The problem I think is:
for ( ; temp->next_ != tail; temp = temp->next_) {
tail = temp;
}
delete temp;
tail->next_ = 0;
tail = temp should be after you find the temp that leads to tail (i.e. outside of the for loop).
Also, temp = not the tail but the one before the tail. So probably you need:
for ( ; temp->next_ != tail; temp = temp->next_) {}
delete tail;
tail = temp;
tail->next_ = 0;
The destructor looks buggy to me: you keep "popping" until empty() returns true, which happens when head is the null pointer. But then you can't call delete on head after the while loop is over...
I don't know if this is the issue, but I would check it.
Another humble tip: you didn't tell us where the seg fault happens... If you run your code with gdb (or if you just put a lot of "cout" in your code), you can detect the line that causes you problems.