Destructor for a linked List - c++

I have a linked_list and currently my destructor is not working properly. Not entirely sure why.
Can somebody explain me how to solve this?
class linked_list {
private:
struct node
{
// String in this node
std::string data;
// Pointer to next node
struct node *next;
};
//First item in the list
struct node *first;
Here is my destructor
linked_list::~linked_list(void)
{
while (first)
{
delete first;
first = first->next;
}
}

The problem lies here:
delete first;
first = first->next;
When you delete first, but then try to access first->next. Cache first->next into a temp variable of type node*, then do delete first to fix this:
struct node* temp;
while (first != NULL)
{
temp = first->next;
delete first;
first = temp;
}

change to
linked_list::~linked_list(void)
{
struct node *next;
while (first != NULL)
{
next = first->next;
delete first;
first = next;
}
}

When you 'delete' first, you actually clear all the links from it. Now, if you try to access some other node using this, will not produce the required result.
First, you have to point that node with some other pointer, so that you still have some link which you can access later.

Related

Wrong output is generating while using linklist

I created a program to make a link list in c++
I have a class CL I am trying to insert nodes at head again and again but this is giving unexpected results.
I tried to insert Nodes using this method
class Node {
public:
string name;
Node* Next;
};
class CL {
public:
Node* head;
public:
CL(void) { head = NULL; } // constructor
Node* insertAtHead(string name); //insert at start of list
void displayList(void);
};
int main()
{
CL poliop;
poliop.insertAtHead("am");
poliop.insertAtHead("a");
poliop.displayList();
}
void CL::displayList(void){
Node* t;
t = head;
while(t != NULL){
cout<<(t->name)<<endl;
t = t->Next;
}
}
Node* CL::insertAtHead(string name)
{
Node temp;
temp.name = name;
temp.Next = head;
head = &temp;
}
OUTPUT
a
a
a
a
a
a
a
a
.
.
.
Just a few quick things that could be causing this:
In your main() function, you don't declare a CL object. So when you make calls to
insertAtHead("am")
insertAtHead("a")
displayList()
it doesn't use those CL functions and does something else. Maybe do something like:
CL list = CL();
list.insertAtHead("am");
list.insertAtHead("a");
list.displayList();
Since you are using pointers for Nodes, instead of NULL you should probably use nullptr:
public:
CL(void) { head = nullptr; } // constructor
In your displayList(void) function, you're using an unidentified variable x?
cout<<(head->x)<<endl;
Maybe it's supposed to be this instead:
cout<<(head->name)<<endl;
BUT, more importantly, in your displayList(void) function you traverse the linked list using the head pointer, in effect, you end up assigning the end of the list to be equal to the head of the linked list as soon as the displayList(void) function finishes execution. I would recommend changing it to look like this instead:
void LinkList::displayList(void){
Node* temp = head;
while(temp != nullptr){
cout<<(temp->name)<<endl;
temp = temp->Next;
}
}
I hope one of these things helps you fix the issue of undefined behavior you're dealing with! c:

Linked list delete

template<typename T>
List<T>::~List()
{
while(head->next !=NULL){
delete head;
head = head->next;
}
head = NULL;
}
I want to delete all the nodes in the linked list, but I don' t know why the code fail.
Your code fails probably because it invokes undefined behaviour.
delete head;
head = head->next;
You cannot read the memory located where head points after having deleted head.
You should make a copy of head->next to reuse it:
const auto next = head->next;
delete head;
head = next;
I would go with the following solution. No invalid memory access, no memory leak, and it automatically assigns NULL to head before leaving the loop:
template<typename T>
List<T>::~List()
{
while (head)
{
Node<T> *next = head->next;
delete head;
head = next;
}
}
Please note that I made a guess with the node type and you have to replace it by whatever is present in your code.
This can help you in deleting every node of linked list.
List<T> *current = head;
while (current != NULL)
{
next = current->next;
delete current;
current = next;
}
It depends what type the head variable is. If it is the class, you can even use "recursive" deleting in "head" (I mean node) destructor. Something similar to:
Node::~Node(){
if(this->next != nullptr)
delete this->next;
delete this->content;
}
If the node is internal struct, you need temporary pointer to next node as mentioned above:
template<typename T>
List<T>::~List()
{
struct nodeType *temp;
while(head != nullptr){
temp = head->next;
delete head;
head = temp;
}
}
In this case, you don't need to explicitly set head to null, since it is done by the logic of while loop.
In your loop (in question) you don't remove *head node, I don't know if it is expected behavior.
Ad. comment above (I can't put it directly):
while(head->next!=NULL){ Node*next = head->next; delete head; head = next; } head = NULL;
is wrong. It doesn't delete last node on the list (especially if the list has only one object, it won't be deleted).

How do I access a specific pointer, within an array of structures?

I have a structure with two pointers that I am storing inside of an array of the same type. I am unsure of how to access the pointers in each specific index of the array.
class List
{
public:
List();
private:
struct L_Node
{
L_Node *next;
L_Node *prev;
int iValue; // not actually doing anything in this example
}
L_Node head[4];
L_Node tail[4];
}
In the constructor, I am wanting head[0] next to be pointing to tail[0] next, head[1] next to tail[1] next and so on, with *prev to be pointing from tail to head to form a doubly linked list. For head, prev = NULL, and in tail next=NULL. In between the head and tail arrays, I am trying to have some dynamic instances of L_Node.
As of now, in my constructor, I have
head->next = new L_Node;
head->prev = NULL;
tail->next = NULL;
tail->prev = new L_Node;
head->next->next = tail;
tail->prev->prev = head;
It compiles, however I am unsure of how it is behaving. Is head[0] pointing through the dynamic struct to tail[0] and so on?
Thanks in advance for any help or tips.
EDIT:
would a typedef for a pointer such as
typedef L_Node *L_Ptr;
be of help?
From your description, this is what you need in the constructor of List:
List::List()
{
for (int i = 0; i != 4; ++i )
{
head[i].next = tail[i];
tail[i].prev = head[i];
}
}
I would add a constructor in L_Node to have sane initial values for its member data.
L_Node() : next(NULL), prev(NULL), iValue(0) {}

delete linked list using recursive function?

struct Node {
int value;
Node* next;
~Node() {
delete next;
}
};
Node* deleteList(Node* p) {
if(p == nullptr) return nullptr;
Node* pNext = p->next;
delete p;
return deleteList(pNext);
}
the compiler said something about bad access.
I tried to set breakpoint to debug it. If the linked list is [3, 2, 1], it first delete the 3, then 2 and 1, and then jump back to 2, then encountered exception.
Can someone tell me what is the problem?
The destructor for the Node struct already calls delete on "next". Therefore, it goes to "next" and calls its destructor, and so on. All nodes following p in the linked list will then be deleted just by calling delete p; (where p is a Node*).
I recommend you get rid of the Node's destructor to prevent this chain destruction from occurring.
struct Node {
int value;
Node* next;
};
As a side note, while I don't know the rest of your code I don't see a reason as to why deleteList(Node* p) should return a Node* (as it will always be nullptr, no interesting results are returned).
void deleteList(Node* p)
{
if(p == nullptr) return;
Node* pNext = p->next;
delete p;
deleteList(pNext);
}
If the linked list is: [3, 2, 1], when you call deleteList, the following things happen:
p = 3, pNext = 2, 3 was deleted by delete p; Then the destructor was called, so delete next would delete 2 and 1 recursively.
then after delete p in deleteList function, deleteList(pNext) was called again, so this time: p = 2, pNext = 1, since 2 was already deleted in the previous step, it would corrupt when you call delete p again.
So please remove the delete next; in ~Node().
Actually I don't see reason why deleteList should be used, because it would always return nullptr and delete all the nodes. So why not remove the deleteList function, and keep the delete next; in ~Node(). You can delete the created Node object directly.
And of course the best way to do this task is: std::list.
I would wager a guess that you are experiencing delete being called multiple times on an instance that has already been deleted. When you call delete p;, p's destructor is getting called, and it is deleting the next node in the list. You then recursively call deleteList, passing it the node that was just deleted by p's destructor, making the pointer you are holding invalid.
What you need to do is determine whether the Node owns the Node that follows it in the list (that is, is it responsible for cleaning it up), or will some outside code take care of that. You cannot do both.
Edit:
As an aside, what you really want is not to have a recursive delete function, but rather a loop within your deleteList function. Something like ...
struct Node {
int value;
Node* next;
};
// Loop in the function; recursion not required, and no return value.
void delete_list(Node* n)
{
Node* tmp;
while (nullptr != n) {
tmp = n->next;
delete n;
n = tmp;
}
}
In this case, the Node instance does not own its sibling Node (Node.next), and takes no responsibility for deallocating it; that is up to the delete_list function.
Remove the line delete next; from the destructor of Node.
I think there may be two choices for you.
first, as R Sahu said, remove the delete next in destructor.
struct Node {
int value;
Node* next;
};
Node* deleteList(Node* p) {
if(p == nullptr) return nullptr;
Node* pNext = p->next;
delete p;
return deleteList(pNext);
}
second, just delete the head node of the link in deleteList, but not delete nodes recursively.
struct Node {
int value;
Node* next;
Node() : value(0), next(nullptr)
{}
~Node() {
if (next != nullptr)
{
delete next;
}
}
};
Node* deleteList(Node* p) {
if (p != nullptr)
{
delete p;
}
return nullptr; // in fact your code always return nullptr. so it just return nullptr here.
}

Appending node to LinkedList

I am trying to create a function that adds a node to the end of a LinkedList. I know how to do it using loops, but my professor wants it done a certain way and I don't understand why it's not working. He practically gave us all the code for it..
This is the pseudo-code he gave us:
process append(data)
if (not the end)
next->append(data);
else
next=new Node();
next->data=data;
next->data = nullptr;
And this is what I came up with:
struct Node {
int data;
Node* next;
};
struct LinkedList {
Node* head;
LinkedList() {head = nullptr;}
void prepend(int data) {
if (head == nullptr) {
Node* tmp = new Node();
tmp->data=data;
tmp->next=nullptr;
}
else {
Node* tmp = new Node();
tmp->data=data;
tmp->next=head;
head=tmp;
}
}
void append(int data) {
Node* tmp = head;
if (tmp->next != nullptr) {
tmp=tmp->next->append(data);
}
else {
tmp->next = new Node();
tmp->next->data = data;
tmp->next->next = nullptr;
}
}
};
int main()
{
LinkedList LL = LinkedList();
LL.prepend(7);
LL.append(6);
std::cout << LL.head->data << std::endl;
}
My prepend (to add to the beginning of the LinkedList) works fine, but when I try this code, I get
main.cpp:48:20: error: 'struct Node' has no member named 'append'
tmp->next->append(data);
So I'm pretty sure that there's something wrong with saying next->append(data), which from what I understood, is supposed to be recursively calling back the append function until it reaches a nullpointer. I'm thinking maybe there's some sort of way to write it, but people in my class are telling me that the next->append(data) thing SHOULD work, so I guess I'm not exactly sure why this isn't doing anything. I tried instead writing the append function in the Node struct, but then it says that head wasn't declared in the scope and I really just don't know how to work with this. I'm also sort of new to classes/structs in C++ so I'm assuming it's something about that that I'm not understanding.
The class Node has not any method named append so you get that error message:
tmp->next->append(data);
^^^^^^^^^^^^^
struct Node {
int data;
Node* next;
};
To append a node to a linked-list, you don't need an append method within Node. Remove that. Correct the append process in LinkedList::append:
void append(int data) {
Node* tmp = head;
while (tmp->next)
tmp = tmp->next;
tmp->next = new Node();
tmp->next->data = data;
tmp->next->next = nullptr;
}
I did't test, but you need something like above code. At first, it tries to access to the end of list. Then it appends a node.
Recursive implementation:
void append(int data) {
append(data, head);
}
void append(int data, Node *node) {
if (node->next)
append(data, node->next);
else {
tmp->next = new Node();
tmp->next->data = data;
tmp->next->next = nullptr;
}
}
Your append method isn't defined on the Struct Node. Instead it's defined on the LinkedList class so you need to invoke it accordingly. You can redefine the append method to take a node as a parameter or add an append method to the Struct Node itself. Also there's no need to assign the result of append to tmp =
Your append method is void.
tmp->next is a Node, so to call append function, you must declare it in Node struct
Like this
struct Node
{
void append(int data)
{
if (next)
next->append(data);
else
{
next = new Node();
next->data = data;
next->next= nullptr;
}
}
int data;
Node* next;
};
it's clear from the pseudo code next->append(data); that append is meant to be a member of Node.
Here's how you might use Node::append from LinkedList::append
class LinkedList {
void append(int data) {
if (head == nullptr) {
head = new Node();
head->data=data;
head->next=nullptr;
}
else {
head->append(data);
}
}
}
The node structure does not contain any append method.
Moreover, you are splitting work that can be done in one methos to two methods, writing more code.
See my answer to another question here with working code I wrote
https://stackoverflow.com/a/37358192/6341507
As you can see, I solve all in method
AddItem(int i)
I start seeing that creating linked list i kindof har for many people here, so I will further edit my answer there to provide additional information.
Good luck!