C++: potential memory leak in linked list - c++

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;
}
}
};

Related

Destructor for circular linked list in 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;
}

All of nodes in linkedlist are the same, seems insertion is not working

I have a linked list in C++, after inserting several nodes now I see that all of them are the same, although I'm using different values to add to node each time, but it's like all of them are the same, even when trying to change a node all of them are changing together or it's the same node that is always being returned, I don't know.
class node
{
public:
int ochance = 3;
string question;
string option1;
int peopleeffectop1;
int courteffectop1;
int treasuryeffectop1;
string option2;
int peopleeffectop2;
int courteffectop2;
int treasuryeffectop2;
node *next;
};
class list
{
private:
node *head, *tail;
public:
list()
{
head=NULL;
tail=NULL;
}
void createnode(int value , string q , string ans1 , int ans1ef1 , int ans1ef2, int ans1ef3 , string ans2, int ans2ef1 , int ans2ef2, int ans2ef3 )
{
node *temp = new node;
temp->ochance = value;
temp->question = q;
temp->option1 = ans1;
temp->peopleeffectop1 = ans1ef1;
temp->courteffectop1 = ans1ef2;
temp->treasuryeffectop1 = ans1ef3;
temp->option2 = ans2;
temp->peopleeffectop2 = ans2ef1;
temp->courteffectop2 = ans2ef2;
temp->treasuryeffectop2 = ans2ef3;
temp->next = NULL;
if(head == NULL)
{
head = temp;
tail = temp;
temp = NULL;
}
else
{
tail->next = temp;
tail = temp;
}
}
node getnth(int pos)
{
node* tmp = new node;
tmp = head;
int i = 0;
while(tmp!=NULL)
{
if (i=pos)
{
return *tmp;
}
i++;
tmp = tmp->next;
}
}
int getlen()
{
node* tmp = new node;
tmp = head;
int i = 0;
while(tmp!=NULL)
{
i++;
tmp = tmp->next;
}
return i;
}
void minus(int pos)
{
node* tmp = new node;
tmp = head;
int i = 0;
while(tmp!=NULL)
{
if (i=pos)
{
tmp->ochance -=1;
}
i++;
tmp = tmp->next;
}
}
void delete_first()
{
node *temp = new node;
temp = head;
head = head->next;
delete temp;
}
void delete_last()
{
node *current = new node;
node *previous = new node;
current = head;
while(current->next != NULL)
{
previous = current;
current = current->next;
}
tail = previous;
previous->next = NULL;
delete current;
}
void delete_position(int pos)
{
node *current = new node;
node *previous = new node;
current = head;
for(int i = 1; i < pos; i++)
{
previous = current;
current = current->next;
}
previous->next = current->next;
}
};
For starters many member functions has a memory leak as for example in this function
node getnth(int pos)
{
node* tmp = new node;
tmp= head;
//
At first memory was allocated and its address was stored in the pointer tmp and then the pointer is reassigned. As a result the address of the allocated memory is lost and the memory is not deleted.
These statements
node* tmp = new node;
tmp= head;
must be substituted for this one statement
node* tmp = head;
Moreover this function
node getnth(int pos)
{
node* tmp = new node;
tmp= head;
int i =0 ;
while(tmp!=NULL){
if (i=pos) {
return *tmp;
}
i++;
tmp = tmp->next;
}
}
has undefined behavior in case when pos is higher than there are nodes in the list. In this case the function returns nothing.
In the function minus there is used the assignment operator instead of the comparison operator
while(tmp!=NULL){
if (i=pos) {
^^^^^
In this function
void delete_first()
{
node *temp=new node;
temp=head;
head=head->next;
delete temp;
}
there is no check whether head is equal to NULL and tail is not adjusted if it is point to the first node.
The same problems are also in the function delete_last only that instead of the adjacent of the tail node as in the previous function you have to adjust the head node.
This function delete_position has the same drawbacks as the previous functions but also it has a bug in the loop
for(int i=1;i<pos;i++)
A node at position 1 will never be deleted.

Find the same elements in C-struct

I have to write a function that will add elements to C-struct, but it can't add the same element. Example:
Input:
1 2 1 3
Output:
ADDED 1
ADDED 2
NOT ADD 1
ADD 3
Elements are taken from array, here's piece of code that uses the function I need to write:
int tab[] = {1,4,1,3,5};
Node* head = 0;
for (size_t i = 0, e = std::size(tab); i != e; ++i) {
bool b = add(head,tab[i]);
cout << tab[i] << (b ? " " : " NOT ")
<< "added" << endl;
}
C-struct Node looks like that:
struct Node {
int data;
Node* next;
};
Here's what I wrote, but it adds all elements from array. I can't change the loop, only add function:
bool add(Node*& head, int data){
Node *n = new Node;
n->data = data;
n->next = 0;
if(!head)
head = n;
else{
Node *tmp = head;
while(tmp->next)
tmp = tmp->next;
tmp->next = n;
}
};
currently you just add the element without looking if it is already present or not
The definition can be something like
bool add(Node*& head, int data){
if(!head) {
head = new Node;
n->data = data;
n->next = 0;
return true;
}
Node *tmp = head;
while (tmp->next) {
if (tmp->data == data)
return false;
tmp = tmp->next;
}
if (tmp->data == data)
return false;
tmp->next = new Node;
tmp->next->data = data;
tmp->next->next = 0;
return true;
}
I encourage you to add a constructor to not have to set the data and next fields each time after you create a new instance
Exemple
Node::Node(int d) : next(0), data(d) {
}
// add should be a static method of Node, to be able to access next and data while they are private
bool add(Node*& head, int data){
if(!head) {
head = new Node(data);
return true;
}
Node *tmp = head;
while (tmp->next) {
if (tmp->data == data)
return false;
tmp = tmp->next;
}
if (tmp->data == data)
return false;
tmp->next = new Node(data);
return true;
}
Here's my attempt. Look for the existing data first then add if not present (no change there from existing code)
bool add(Node*& head, int data) {
Node *tmp = head;
while (tmp) {
if (tmp->data == data)
return false; // data already present
tmp = tmp->next;
}
Node *n = new Node;
n->data = data;
n->next = 0;
if (!head) {
head = n;
}
else {
Node *tmp = head;
while(tmp->next)
tmp = tmp->next;
tmp->next = n;
}
return true; // data added
}
So I did something like that and it works with the data I have. I suppose it works in general
bool add(Node*& head, int data){
Node *n = new Node;
n->data = data;
n->next = 0;
if(!head)
head = n;
else{
Node *tmp = head;
while(tmp->next){
if(tmp->data == data)
return false;
else
tmp = tmp->next;
}
tmp->next = n;
}
};

changing linked list into a doubly linked list

Hi could you please help me change this linked list into a doubly linked list ?
I would be very grateful for help :)
#include <iostream>
using namespace std;
template <class T>
struct node
{
T data;
node<T> *next;
node<T> *prev;
};
template <class T>
class Container
{
public:
//constructs a new empty Kontener
Container()
{
head = new node<T>;
head->next = head;
head->prev = head;
};
//constructs a new jp_list that is a copy of an existing list
Container(const Container<T>& rt_side)
{
head = new node<T>;
head->next = head;
head->prev = head;
node<T> *crt_ptr = rt_side.head->next;
while(crt_ptr != rt_side.head)
{
push_back(crt_ptr->data);
crt_ptr = crt_ptr->next;
}
};
//adds a data node to the front of the list
void push_front(T nw_data)
{
node<T> *temp = new node<T>;
temp->data = nw_data;
temp->next = head->next;
head->next->prev = temp;
temp->prev = head;
head->next = temp;
};
//adds a data node to the end of the list
void push_back(T nw_data)
{
node<T> *temp = new node<T>;
temp->data = nw_data;
head->prev->next = temp;
temp->prev = head->prev;
temp->next = head;
head->prev = temp;
};
//removes the first node and returns the data
T pop_front()
{
node<T> *temp = head->next;
T temp_data = head->next->data;
head->next = temp->next;
temp->next->prev = head;
delete temp;
return temp_data;
};
//removes the last node and returns the data
T pop_back()
{
node<T> *temp = head->prev;
T temp_data = head->prev->data;
head->prev = temp->prev;
temp->prev->next = head;
delete temp;
return temp_data;
};
//resturns the size of the list
int size()
{
int size = 0;
node<T> *crt_ptr; //pointer to current node
crt_ptr = head->next;
while(crt_ptr != head)
{
size += 1;
crt_ptr = crt_ptr->next; //advance to the next node then loop
}
return size;
};
//prints out all the data in the list
void display_all()
{
node<T> *crt_ptr = head->next;
for(int i = 0; crt_ptr != head; i++)
{
cout << "Node " << (i+1) << ": " << crt_ptr->data << endl;
crt_ptr = crt_ptr->next;
}
};
Container& operator= (const Container& rt_side)
{
if(this == &rt_side)
return *this;
node<T> *crt_ptr = head->next;
//empty this list so the rt_side can be coppied in
while(crt_ptr != head)
{
crt_ptr = crt_ptr->next;
pop_front();
}
crt_ptr = rt_side.head->next;
while(crt_ptr != rt_side.head)
{
push_back(crt_ptr->data);
crt_ptr = crt_ptr->next;
}
return *this;
};
virtual ~Container()
{
int list_size = size();
for(int i = 0; i < list_size; i++)
{
pop_front();
}
delete head;
};
private:
node<T> *head;
};
#endif
I am just a beginner so please help me :)
The tail would always point to the last item that was inserted into the list.
However, I do not think that having a tail pointer makes it necessarily a doubly linked list. A singly linked list can also have a tail pointer (however useless it might be). I believe you are asking to create a double ended doubly linked list.
You already have the next and previous pointers to enable the double link. All you have to do, is when you push something into the list, you need to make the tail pointer point to the node that is being added. Similarly, when removing a node, you need the tail pointer to point to tail's previous BEFORE deleting the last node.
* UPDATE *
Here is some code. I am assuming a double ended doubly linked list with two ends.
void push_front(T nw_data)
{
node<T> *temp = new node<T>;
temp->data = nw_data;
if(head == nullptr)
{
head = temp;
tail = temp;
}
else if(head == tail)
{
head->next = temp;
temp->prev = head;
tail = temp;
}
else
{
temp->next = head->next;
head->next->prev = temp;
temp->prev = head;
head->next = temp;
}
};
//adds a data node to the end of the list
void push_back(T nw_data)
{
node<T> *temp = new node<T>;
temp->data = nw_data;
if(head == nullptr)
{
head = temp;
tail = temp;
}
else if(head == tail)
{
head->next = temp;
temp->prev = head;
tail = temp;
}
else
{
temp->prev = tail;
tail->next = temp;
tail = temp;
}
};
T pop_back()
{
node<T> *temp = tail;
T temp_data = tail->data;
tail = tail->prev;
tail->next = null;
delete temp;
return temp_data;
};
* UPDATE * Copy Constructor
In your copy constructor, if the push_back sets the tail, then all you need to do is to push_back the nodes like you are doing. head->next = head and head->prev = head makes the linked list cyclical.
Container(const Container<T>& rt_side)
{
this->head = rt_side.head;
node<T> * crt_ptr = rt_side.head->next;
while (crt_ptr != null)
{
push_back(crt_ptr->data);
crt_ptr = crt_ptr->next;
}
};

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.