How to fix memory leak with linked list? - c++

Hi I have the following code, and keep getting memory leaks, can someone help me fix this please, I've been at this for hours but cant seem to find why there is a memory leak, I am new with nodes, I think the problem is with the destructor, but can't seem to pin point exactly what, please help!
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* next;
};
class LinkedList {
public:
LinkedList() { // constructor
head = NULL;
}
~LinkedList(); // destructor
void insert(int val);
void display();
private:
Node* head;
};
LinkedList::~LinkedList() { delete head; }
// function to add node to a list
void LinkedList::insert(int val) {
Node* newnode = new Node();
newnode->data = val;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
} else {
Node* temp = head; // head is not NULL
while (temp->next != NULL) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
void LinkedList::display() {
if (head == NULL) {
cout << "List is empty!" << endl;
} else {
Node* temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
}
int main() {
LinkedList* list = new LinkedList();
list->insert(999);
list->insert(200);
list->insert(300);
list->insert(700);
list->insert(500);
cout << "Linked List data" << endl;
list->display();
delete list;
return 0;
}

An alternative to Abel's answer with the Node-destroying Nodes:
LinkedList::~LinkedList()
{
while (head)
{
Node * temp = head;
head = head->next;
delete temp;
}
}
The LinkedList loops removes, and deletes the first Node until there are no Nodes left.
Why do I prefer this approach? Two reasons:
Ownership. Who is responsible for managing the nodes? With the loop, managing the Nodes is entirely in the hands of LinkedList. If Nodes can destroy one another, management is split between LinkedList and Node, and both owners need to remain in agreement about the state of the managed resource. Maintaining this agreement is tricky and tricky means more code you can get wrong. For example, if LinkedList isn't careful when removing a single Node from the list, that Node will recursively destroy the rest of the list. Ooops.
The second reason is recursion. If the list gets too long, the program will exhaust its automatic storage (Usually causing a Stack Overflow) and become unstable. You've limited the size of the list you can handle unnecessarily and the only way you'll know you've exceeded the limit is when the program fails.
The access violation the Asker has been experiencing I have been unable to reproduce. I may have accidentally fixed it.

I don't think you want destructing a node to delete the entire list. You could but I think each node should be independent of the others - the linked list class is where list level things should happen.
Also, you don't want the destructor to contain the code to clear the list because you may want to clear the list at some arbitrary point - so the linked list should have a clear function that is called from the linked list destructor and can be called from other places too.
So the destructor would call this function to clear the list:
void LinkedList::clear() {
Node* next;
Node* temp = head;
while (temp != NULL) {
next = temp->next;
delete temp;
temp = next;
}
head = NULL;
}
The whole code would be:
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* next;
Node() : data(0), next(NULL) {
cout << "Constructed default node\n";
}
Node(int data) : data(data), next(NULL) {
cout << "Constructed node: " << data << "\n";
}
~Node() {
cout << "Destructed node: " << data << "\n";
}
};
class LinkedList{
public:
LinkedList() { // constructor
head = NULL;
}
~LinkedList() {
clear();
}
void insert(int val);
void display();
void clear();
private:
Node* head;
};
// function to add node to a list
void LinkedList::insert(int val) {
Node* newnode = new Node(val);
if (head == NULL) {
head = newnode;
}
else {
Node* temp = head; // head is not NULL
while (temp->next != NULL) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
// function to delete the entire list
void LinkedList::clear() {
Node* next;
Node* temp = head;
while (temp != NULL) {
next = temp->next;
delete temp;
temp = next;
}
head = NULL;
}
// function to display the entire list
void LinkedList::display() {
if (head == NULL) {
cout << "List is empty!" << endl;
}
else {
Node* temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
}
int main() {
LinkedList list;
cout << "Creating List\n";
list.insert(999);
list.insert(200);
list.insert(300);
list.insert(700);
list.insert(500);
cout << "Linked List data:\n";
list.display();
cout << "Clearing list\n";
list.clear();
cout << "Creating List\n";
list.insert(400);
list.insert(600);
cout << "Linked List data:\n";
list.display();
cout << "NOT clearing list (should happen automatically\n";
return 0;
}
You can try it here: https://onlinegdb.com/HJlOT1ngqP
The output:
Creating List
Constructed node: 999
Constructed node: 200
Constructed node: 300
Constructed node: 700
Constructed node: 500
Linked List data:
999 200 300 700 500
Clearing list
Destructed node: 999
Destructed node: 200
Destructed node: 300
Destructed node: 700
Destructed node: 500
Creating List
Constructed node: 400
Constructed node: 600
Linked List data:
400 600
NOT clearing list (should happen automatically
Destructed node: 400
Destructed node: 600

Related

I read the input number with getchar(), why is the number reversed in the linked list?

I typed 1234, but the list has 4,3,2,1 in it. I suspect the problem is getchar() itself, or a function in the class, but I have no way to find out.
The link class is responsible for some linked list operations, such as deletion, insertion, etc., while the node class is responsible for creating and assigning nodes.
The createlist class is responsible for the creation of the linked list, which is the main source of the problem. I wrote the debug statement in it, so you can run it and see the results for yourself
using namespace std;
class Node
{
public:
int data;
Node *next;
Node()
{
next = nullptr;
}
Node(int data)
{
this->data = data;
}
Node(const Node &temp)
{
this->data = temp.data;
}
};
class Link
{
public:
Node *head;
int length = 0;
Link()
{
head = new Node();
}
~Link()
{
while (head != nullptr)
{
Node *p = head->next;
free(head);
head = p;
}
}
void insert(const Node &cache)
{
Node *temp = new Node(cache);
temp->next = head->next;
head->next = temp;
length++;
}
};
void Creatlist(Link &link)
{
char cache;
while (1)
{
cache = getchar();
if (cache == '\n')
break;
link.insert(Node(cache - '0'));
cout << cache << " ";
}
cout<<endl;
Node *p = link.head->next;
cout << "in the linklist:";
while (p != nullptr)
{
cout << p->data << " ";
p = p->next;
}
}
int main()
{
Link link;
cout<<"inut numbers:"<<endl;
Creatlist(link);
}```
With the insert you inserted to the FRONT of the list. So you had "1", then "2->1" ... If you want to insert to the end, don't insert at the head, but hake a Node* tail in the class Link and an insert_end function as
//...
Node* temp;
void insert_end(const Node &cache){
Node *temp = new Node(cache);
tail->next=temp;
tail=tail->next;
length++;
}
Alsoin the constructor set tail=head

C++ linked list implementation, goes to infinite loop while traversing. Guessing something is wrong with the contructors

I'm new to C++. I'm trying to implement a linked list. The output goes to an infinite loop when the traverse function is called(output shown at the bottom). Had no errors when I used 'new' in the insertNodeAtEnd function instead of contructors, but I read up that it's generally not a good practice in C++ and it's better to get accustomed to using constructors.
What am I doing wrong?
#include <iostream>
struct Node
{
int data;
Node *next;
Node(int data)
{
this->data = data;
this->next = NULL;
}
~Node() {}
};
class LinkedList
{
public:
LinkedList()
{
std::cout << "Linked list created \n";
}
static Node *head;
static Node *tail;
static int numberOfNodes;
static int getNumberOfNodes()
{
return numberOfNodes;
}
static void insertNodeAtEnd(int data)
{
Node newNode(data);
if (head == NULL)
{
head = tail = &newNode;
return;
}
tail->next = &newNode;
tail = &newNode;
numberOfNodes++;
return;
}
static void traverse()
{
if (numberOfNodes == 0)
{
std::cout << "Linked list is empty \n";
}
Node *curr = head;
while (curr != NULL)
{
std::cout << curr->data << std::endl;
curr = curr->next;
}
return;
}
~LinkedList()
{
std::cout << "Linked list destroyed \n";
}
};
Node *LinkedList::head = NULL;
Node *LinkedList::tail = NULL;
int LinkedList::numberOfNodes = 0;
int main()
{
LinkedList linkedlist;
linkedlist.insertNodeAtEnd(40);
linkedlist.insertNodeAtEnd(50);
linkedlist.insertNodeAtEnd(60);
linkedlist.insertNodeAtEnd(70);
linkedlist.traverse();
}
And here's the output. (Infinite loop, had to terminate in the console.)
Linked list created
70
70
70
70
70
70
70
Here:
static void insertNodeAtEnd(int data)
{
Node newNode(data);
if (head == NULL)
{
head = tail = &newNode;
return;
}
tail->next = &newNode;
tail = &newNode;
numberOfNodes++;
return;
}
newNode is a function local variable. Its lifetimes ends when the function returns. The pointers you store are dangling. When you dereference them later you invoke undefined behavior.
To dynamically allocate the nodes, such that they persist you can do
Node* newNode = new Node(data);
It is not clear why all members of LinkedList are declared static. The effect is basically that you can only have one linked list, because a second one would share all members.
I got it to work by instead creating a new Node rather than directly instantiating one. What happens in your version is that the created node is destroyed while by creating a new one it will remain valid until explicitly deleted
#include <iostream>
struct Node
{
int data;
Node *next;
Node(int data)
{
this->data = data;
this->next = NULL;
}
~Node() {}
};
class LinkedList
{
public:
LinkedList()
{
std::cout << "Linked list created \n";
}
static Node *head;
static Node *tail;
static int numberOfNodes;
static int getNumberOfNodes()
{
return numberOfNodes;
}
static void insertNodeAtEnd(int data)
{
Node* newNode = new Node(data);
if (head == NULL)
{
head = tail = newNode;
return;
}
tail->next = newNode;
tail = newNode;
numberOfNodes++;
return;
}
static void traverse()
{
if (numberOfNodes == 0)
{
std::cout << "Linked list is empty \n";
}
Node *curr = head;
while (curr != NULL)
{
std::cout << curr->data << std::endl;
curr = curr->next;
}
return;
}
~LinkedList()
{
std::cout << "Linked list destroyed \n";
}
};
Node *LinkedList::head = NULL;
Node *LinkedList::tail = NULL;
int LinkedList::numberOfNodes = 0;
int main()
{
LinkedList linkedlist;
linkedlist.insertNodeAtEnd(40);
linkedlist.insertNodeAtEnd(50);
linkedlist.insertNodeAtEnd(60);
linkedlist.insertNodeAtEnd(70);
linkedlist.traverse();
}

Will there be a memory leak in this Linked list

Hi Currently i have been honing my skill in the data structure so that i can become a good Game Developer, i am Learning Linked list and made a Linked list Program with Insertion ,Deletion and Recursive insertion and Reversing a Linked list Can you Guys tell me am i here Clearing the assigned memory Created with the new Operator Correctly, I am getting the Desired Output but i am worried about memory leak. ... please be gentle aim Still learning.
class Node
{
int data;
Node *Next;
public:
int GetData()
{
return data;
}
void SetData(int Data)
{
data = Data;
}
Node *GetNext()
{
return Next;
}
void SetNext(Node *next)
{
Next = next;
}
};
void Insert(Node **Head, int x)
{
Node *temp = new Node();
temp->SetData(x);
temp->SetNext(*Head);
*Head = temp;
}
void InsertAt(Node **Head, int x, int n)
{
if (n == 0)
{
std::cout << "The Given data at 'n' cannot be assigned to null\n";
}
Node *temp = new Node();
temp->SetData(x);
if (n == 1)
{
temp->SetNext(nullptr);
*Head = temp;
return;
}
Node *temp2 = *Head;
if (Head == nullptr)
{
std::cout << "The Given data cannot be assigned to null\n";
}
for (int i = 0; i < n - 2; i++)
{
temp2 = temp2->GetNext();
}
temp->SetNext(temp2->GetNext());
temp2->SetNext(temp);
}
void AppendList(Node **Head, int Data)
{
Node *temp = new Node();
Node *LastNode = *Head;
temp->SetData(Data);
temp->SetNext(nullptr);
if (*Head == nullptr)
{
*Head = temp;
return;
}
// else Traverse till last node.
while (LastNode->GetNext() != nullptr)
{
LastNode = LastNode->GetNext();
}
LastNode->SetNext(temp);
}
void DeleteNode(Node **Head, int n)
{
Node *temp = *Head;
if (n == 1)
{
*Head = temp->GetNext();
std::cout << "\nAfter Deletion of Head Node\n";
return;
}
for (int i = 0; i < n - 2; i++)
{
temp = temp->GetNext();
}
Node *temp2 = temp->GetNext();
temp->SetNext(temp2->GetNext());
std::cout << "After Deletion of Node\n";
}
Node *ReverseList(Node *Head)
{
Node *Current, *Prev, *next;
Current = Head;
Prev = nullptr;
while (Current != nullptr)
{
next = Current->GetNext();
Current->SetNext(Prev);
Prev = Current;
Current = next;
}
Head = Prev;
return Head;
}
int LinkedList_Count(Node *Head)
{
int count = 0;
Node *Current = Head;
while (Current != nullptr)
{
count++;
Current = Current->GetNext();
}
std::cout << "Number of Elements: " << count;
return count;
}
void PrintList(Node *Head)
{
std::cout << "Data list : ";
while (Head != nullptr)
{
std::cout << " " << Head->GetData();
Head = Head->GetNext();
}
std::cout << "\n";
}
//Print Listed using Recursion
void Recursion_Print(Node *Head)
{
if (Head == nullptr)
{
return;
}
std::cout << ' ' << Head->GetData(); //comment to Do Reverse the Linked list
Recursion_Print(Head->GetNext());
//std::cout << ' ' << Head->GetData();//unComment to Reverse the linked List recursively
}
Node *RecursiveRevList(Node *Head)
{
Node *temp;
if (Head->GetNext() == nullptr)
{
temp = Head;
return temp;
}
temp = RecursiveRevList(Head->GetNext());
Head->GetNext()->SetNext(Head);
Head->SetNext(nullptr);
return temp;
}
void RunList()
{
Node *Head = NULL;
//AppendList(&Head, 16);
Insert(&Head, 6);
Insert(&Head, 7);
Insert(&Head, 8);
InsertAt(&Head, 18, 2);
std::cout << "Data list : \n";
Recursion_Print(Head);
std::cout << '\n';
LinkedList_Count(Head);
DeleteNode(&Head, 1);
//Head = ReverseList(Head);
Head = RecursiveRevList(Head);
PrintList(Head);
LinkedList_Count(Head);
delete Head;
}
You're writing C-style code; in C++, you should avoid explicit calls to new. Your example is far too long to rewrite, but here is a very small start:
#include <memory>
class Node
{
int data;
std::shared_ptr<Node> Next;
// ...
void Insert(std::shared_ptr<Node>& Head, int x)
{
auto temp = std::make_shared<Node>();
// ...
}
(Note that std::unique_ptr is probably a better choice than std::shared_ptr, but that incurs complications with copying Node of which you're "blissfully" unaware right now.)
And, in practice, you should really use std::list (in your case, std::list<int>) rather than writing your own. Once you're proficient using std::list (and friends like std::vector), you'll be better able to "roll your own."
As pointed out in the comments by many learned people, you have a memory leak in your program. When you are deleting the nodes, you're not actually freeing the allocated memory locations. The correct way? Use delete to deallocate the memory from the program.
I would recommend you to learn it as a rule of thumb, when programming in C or C++, if you're allocating dynamic memory somewhere in your program, then in all certainty you'd have some deletion method where you should use free() or delete to deallocate the memory from the heap.
Here are some resources which might help you.
https://www.geeksforgeeks.org/g-fact-30/
https://www.geeksforgeeks.org/delete-in-c/
https://en.cppreference.com/w/cpp/language/delete (might be a little hard if you're a beginner)

How do you print a linked list recursively in C++

I followed a guide on youtube by Paul Programming to create this linked list. Now I want to expand on it. I am trying to learn how to do recursive functions.
The error I am getting is that head isn't declared in main.cpp. I was wondering if anyone could shed some light on the issue I am having.
Code:
main.cpp:
#include <cstdlib>
#include <iostream>
#include "linkedlist.h"
using namespace std;
int main(int argc, char** argv)
{
List list;
list.addNode(1);
list.addNode(2);
list.addNode(3);
list.addNode(4);
list.addNode(5);
cout << "Printing list" << endl;
list.printList();
cout << "Printing list recursively" << endl;
list.printListRecur(head);
return 0;
}
linkedlist.h:
#ifndef _LINKEDLISTHEADER_
#define _LINKEDLISTHEADER_
class List{
private:
typedef struct node{
int data;
node* next;
}* nodePtr;
nodePtr head;
nodePtr curr;
nodePtr temp;
public:
List();
void addNode(int addData);
void deleteNode(int delData);
void printList();
void printListRecur(nodePtr head);
};
#endif
linkedlist.cpp:
#include <iostream>
#include <cstdlib>
#include "linkedlist.h"
using namespace std;
List::List()
{
head = NULL;
curr = NULL;
temp = NULL;
}
void List::addNode(int addData)
{
nodePtr n = new node;
n->next = NULL;
n->data = addData;
if(head != NULL)
{
curr = head;
while(curr->next != NULL)
{
curr = curr->next;
}
curr->next = n;
}
else
{
head = n;
}
}
void List::deleteNode(int delData)
{
nodePtr delPtr = NULL;
temp = head;
curr = head;
while(curr != NULL && curr->data != delData)
{
temp = curr;
curr = curr->next;
}
if(curr == NULL)
{
cout << delData << " was not in the list." << endl;
delete delPtr;
}
else
{
delPtr = curr;
curr = curr->next;
temp->next = curr;
if(delPtr == head)
{
head = head->next;
temp = NULL;
}
delete delPtr;
cout << "The value " << delData << " was deleted" << endl;
}
}
void List::printList()
{
curr = head;
while(curr != NULL)
{
cout << curr->data << endl;
curr = curr->next;
}
}
void List::printListRecur(nodePtr head)
{
if(head == NULL)
{
return;
}
cout << head->data <<endl;
printListRecur(head->next);
}
To use recursion, you need to have the passed and returned data to be the same type, i.e, the function should consume a Node and then return a Node, recursion call will not be formed if function consumes a List but return a Node.
From my understanding, List can be a wrapper class for Node. To give you a very simple example:
class List {
struct Node {
int data;
Node *next;
void print();
...
};
Node *head;
public:
void print();
...
};
void List::Node::print() {
std::cout << data << endl;
if (next) next->print();
}
void List::print() {
if (head) head->print();
}
List will have all the interface methods that a client might need, but the actual work is done by the methods of Node, if you want to go with the recursion way (iteration is more frequently used since recursion consumes much more memory space).
head is a (private) member of the List class. There is no variable named head in main(), that is why the compiler is complaining.
I would suggest either:
adding a method to List to return the head node, then you can pass it to printListRecur():
class List {
...
public:
...
nodePtr getHead() { return head; }
...
void printListRecur(nodePtr node);
...
};
list.printListRecur(list.getHead());
remove the input parameter from printListRecur(), and then define a private method for printListRecur() to call recursively, passing it the head node:
class List {
private:
...
void internalPrintListRecur(nodePtr node);
...
public:
...
void printListRecur();
...
};
void List::internalPrintListRecur(nodePtr node)
{
if (node)
{
cout << node->data <<endl;
internalPrintListRecur(node->next);
}
}
void List::printListRecur()
{
internalPrintListRecur(head);
}
But, as others stated in comments, iterating through the list recursively is not usually desired due to the fact that data may have to be pushed onto the call stack on each iteration. Using recursion to iterate a large list is subject to a stack overflow error, unless the code is written in a way that allows the compiler to apply tail call optimization to avoid the stack error.
In this example, it is better to just use a simple iterative loop instead, like your printList() is already using. Don't use recursion.

Unable to grow my linked list

Given below is my code snippet for linked list. I am not able to add number. Whenever I try to add to my list, numbers are getting replaced, so my list never grows. Can you please let me know what is wrong in this code. It would also be very helpful if you could comment on my coding fashion.
using namespace std;
struct node
{
int number;
std::shared_ptr<node> next;
};
bool isEmpty(std::shared_ptr<node> &head)
{
return (head == NULL);
}
void add(std::shared_ptr<node> &head, int number)
{
std:: shared_ptr<node> temp;
temp.reset(new node);
//temp = head;
cout<<"\n Adddress of head: "<<head.get();
// cout<<"\nAddress of temp: "<<temp.get();
if(isEmpty(head))
{
head.reset(new node);
head->number = number;
head->next = NULL;
cout<<"\nAdded first element";
}
else
{
cout<<"\nAdding element to exisiting list";
while(head->next!= NULL)
{
cout<<"\n traversing to next element----->"<<temp->number;
head = head->next;
}
shared_ptr<node> newNode;
newNode.reset(new node);
newNode->number = number;
newNode->next = NULL;
head->next = newNode;
cout<<"\n address of newNode: "<<newNode.get();
// head->next = temp;
}
//cout<<"\nExiting add";
}
int main()
{
int number;
std::shared_ptr<node> head(nullptr);
char choice;
add(head, number);
return 0;
}
Let's take a walk through the add function. I've tweaked the indentation for easier reading.
void add(std::shared_ptr<node> &head, int number)
{
std::shared_ptr<node> temp;
temp.reset(new node);
What are you using temp for? Nothing that I can see.
//temp = head;
cout << "\n Adddress of head: " << head.get();
// cout<<"\nAddress of temp: "<<temp.get();
if (isEmpty(head))
{
head.reset(new node);
head->number = number;
head->next = NULL;
cout << "\nAdded first element";
}
OK. That case looks good.
else
{
cout << "\nAdding element to exisiting list";
while (head->next != NULL)
{
cout << "\n traversing to next element----->" << temp->number;
head = head->next;
Whups! Just moved the head. You just lost that first node element. No one points at it anymore. Shared pointer prevents the leak by destroying it for you. Nice, but you've still lost the data. Fortunately head points to the former head->next, preventing destruction when the former head goes to its grave with next. Shared pointer saves your bacon, but injects a load of extra overhead.
}
shared_ptr<node> newNode;
newNode.reset(new node);
newNode->number = number;
newNode->next = NULL;
head->next = newNode;
cout << "\n address of newNode: " << newNode.get();
// head->next = temp;
}
//cout<<"\nExiting add";
}
On the coding style front, I would use a Linked List class to make this a bit easier to deal with:
#include <iostream>
class LinkedList // Ahhhr. Here be the class
{
struct node // node is a private member of the class hidden away from sight.
{
int number;
node * next;
};
node * head; // no shared pointer. We'll handle the memory ourselves.
public:
LinkedList(): head(nullptr) // construct and init LinkedList
{
}
// we need a copy constructor to be Rule of Three compliant
LinkedList(const LinkedList & src): head(nullptr) // copy constructor
{
node * cur = src.head;
while (cur != nullptr)
{
add(cur->number);
cur = cur->next;
}
}
~LinkedList() // free up the nodes
{
while (head->next != nullptr)
{
node *temp = head;
head = head->next;
delete temp;
}
delete head;
}
// Need assignment operator to be Rule of Three compliant
// OK this looks a bit weird. src is passed by reference which will
// trigger the copy constructor above to do the copy for us. Then we
// steal the head from the copy and null it so when src goes out of
// scope the destructor doesn't kill all the nodes we just took.
// This is called the Copy-and-Swap idiom.
LinkedList & operator=(LinkedList src)
{
head = src.head;
src.head = nullptr;
return *this;
}
bool isEmpty() // essentially unchanged. head is now a class member.
// No need for parameter
{
return (head == NULL);
}
void add(int number)
{
// removed dead code
if (isEmpty())
{
head = new node;
head->number = number;
head->next = NULL;
}
else
{
node * cur = head; // updates a temporary, not the head.
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = new node;
cur->next->number = number;
cur->next->next = NULL;
}
}
};
// and a quick tester
int main()
{
LinkedList list;
list.add(1);
list.add(2);
list.add(3);
return 0;
}
This allows the Linked List to easily be templated and saves trouble later.
More on the Rule of Three and Copy-and-Swap
Why are you using reset on shared pointer?
http://en.cppreference.com/w/cpp/memory/shared_ptr/reset
Check the following example:
https://codereview.stackexchange.com/questions/33136/singly-linked-list-with-smart-pointers