Getting unhandled exception in double linked list in C++ - c++

I created a doubly-linked list in C++. Everything works great if I insert a node at the beginning of the list or if I just insert a node at the end of the list; but, when I insert a node at the beginning and then try to insert a node at the end, I get a null pointer error!
Here is the code and the problem is in the InserAtEnd function
#include <iostream>
using namespace std;
struct Node {
int data;
Node* prev;
Node* next;
};
struct MyList {
Node* head;
Node* tail;
};
bool IsEmpty(MyList list) {
if (list.head == nullptr) return true;
else return false;
}
void Insert(MyList& list, int data) {
Node* node = new Node();
node->data = data;
node->prev = nullptr;
node->next = list.head; //node->next points to NULL
if (list.head == nullptr) {
list.head = node;
node->prev = nullptr;
}
else {
//insert the new node at the beginning of the list
list.head->prev = node;
list.head = node;
node->prev = nullptr;
}
}
// Insert node at end of list
void InsertAtEnd(MyList& list, int data) {
Node* node = new Node();
node->data = data;
node->next = nullptr;
node->prev = nullptr;
if (list.head == nullptr) { // Empty list
list.head = node;
list.tail = node;
}
else {
list.tail->next = node;
node->prev = list.tail;
list.tail = node;
}
}
//Traverse the list from the head
void PrintAll(const MyList& list) {
Node* temp = list.head;
if (temp == nullptr) {
cout << "list is empty" << endl;
}
else {
while (temp != nullptr)
{
cout << temp->data << endl;
temp = temp->next;
}
cout << "*************************************" << endl;
}
}
Node* Search(const MyList& list, int key) {
Node* temp = list.head;
while (temp != nullptr && temp->data != key)
{
temp = temp->next;
}
return temp;
}
void Delete(MyList& list, int key) {
Node* temp = Search(list, key); //call search()
if (temp != nullptr)
{
if (temp->prev != nullptr)
{
temp->prev->next = temp->next;
}
else
{
list.head = temp->next;
}
if (temp->next != nullptr)
{
temp->next->prev = temp->prev;
}
}
}
int main() {
MyList list;
list.head = nullptr; //initialize the linked-list
list.tail = nullptr;
if (IsEmpty(list))
cout << "List is empty" << endl;
Insert(list, 10);
PrintAll(list);
/*
Insert(list, 20);
Insert(list, 30);
Insert(list, 40);
*/
// Insert at end
cout << "Now insert at end" << endl;
InsertAtEnd(list, 70);
InsertAtEnd(list, 45);
InsertAtEnd(list, 59);
InsertAtEnd(list, 12);
InsertAtEnd(list, 33);
PrintAll(list);
/*
int x = 24;
Node* result = Search(list, x);
if (result == nullptr) cout << "Cannot find " << x << endl;
else cout << "Found " << result->data << endl;
Delete(list, 200);
PrintAll(list);
Delete(list, 10);
PrintAll(list);
Delete(list, 40);
PrintAll(list);
Delete(list, 20);
PrintAll(list);
Delete(list, 30);
PrintAll(list);
*/
return 0;
}

the problem is in the InserAtEnd function
How do you know?
In fact the problem isn't in InserAtEnd but in Insert:
You never set list.tail.
Tip: use Node **tail = &head; for a more efficient MyList and add member initializers and a Constructor.
This is C++ with classes. Use member functions.

Related

insert method for doubly linked list C++

I am implementing doubly linked list in C++, and I have been trying to make my insert method work without success.
The class should contain two node pointers: one to the head of the list, and one to the tail of the list. If the list is empty, they should both point to nullptr.
The insert method should take a value at given index and add it to the list, increasing its size with one element. my code is:
#include <iostream>
#include <vector>
using namespace std;
struct Node
{
int value;
Node *next;
Node *prev; //previous node pointer
Node(int v) : value(v), next(nullptr), prev(nullptr) {}
};
class LinkedList
{
private:
Node *head;
Node *tail;
Node *prev;
Node *get_node(int index)
{
if (index < 0 or index >= size)
{
throw range_error("IndexError: Index out of range");
}
Node *current = head;
for (int i = 0; i < index; i++)
{
current = current->next;
}
return current;
}
public:
int size;
LinkedList()
{
head = nullptr;
tail = nullptr;
}
int length()
{
Node *current = head;
int count = 0;
while (current != nullptr)
{
count++;
current = current->next;
}
cout << "Length of list is " << count << endl;
return count;
}
void append(int value)
{
Node *new_node = new Node(value);
if (head == nullptr)
{
head = new_node;
head->prev = nullptr;
new_node->next = tail;
}
else if (tail == nullptr)
{
tail = new_node;
new_node->next = nullptr;
}
}
void print()
{
Node *current = head;
Node *prev;
cout << "[";
if (current->next == NULL)
{
cout << current->value;
cout << "]";
}
else
{
while (current->next != nullptr)
{
cout << current->value;
cout << ", ";
prev = current;
current = current->next;
}
cout << current->value << "]" << endl;
}
}
~LinkedList()
{
Node *current;
Node *next;
current = head;
while (current != nullptr)
{
next = current->next;
delete current;
current = next;
}
}
int &operator[](int index)
{
return get_node(index)->value;
}
void insert(int val, int index)
{
Node *current = new Node(val);
Node *prev = get_node(index - 1);
Node *next = current->next;
prev->next = current;
}
};
int main()
{
LinkedList a;
a.append(1); // Appending elements to list
a.append(2);
a.append(3);
a.append(4);
a.append(5);
a.print(); // [1, 2, 3, 4, 5]
a.insert(3, 1);
a.print();
};
This gives me the error
libc++abi.dylib: terminating with uncaught exception of type std::range_error: IndexError: Index out of range
Abort trap: 6
I tried to fix all of your methods, probably succeded, at least current test example is printing correct answer:
Try it online!
#include <iostream>
#include <vector>
using namespace std;
struct Node
{
int value;
Node *next;
Node *prev; //previous node pointer
Node(int v) : value(v), next(nullptr), prev(nullptr) {}
};
class LinkedList
{
private:
Node *head;
Node *tail;
Node *get_node(int index)
{
if (index < 0)
throw range_error("IndexError: Index out of range");
Node *current = head;
for (int i = 0; i < index; i++) {
if (!current)
break;
current = current->next;
}
if (!current)
throw range_error("IndexError: Index out of range");
return current;
}
public:
LinkedList()
{
head = nullptr;
tail = nullptr;
}
int length()
{
Node *current = head;
int count = 0;
while (current != nullptr)
{
count++;
current = current->next;
}
cout << "Length of list is " << count << endl;
return count;
}
void append(int value)
{
Node *new_node = new Node(value);
if (head == nullptr)
{
head = new_node;
tail = head;
}
else
{
tail->next = new_node;
new_node->prev = tail;
tail = new_node;
}
}
void print()
{
Node *current = head;
cout << "[";
if (current->next == NULL)
{
cout << current->value;
cout << "]";
}
else
{
while (current->next != nullptr)
{
cout << current->value;
cout << ", ";
current = current->next;
}
cout << current->value << "]" << endl;
}
}
~LinkedList()
{
Node *current;
Node *next;
current = head;
while (current != nullptr)
{
next = current->next;
delete current;
current = next;
}
}
int &operator[](int index)
{
return get_node(index)->value;
}
void insert(int val, int index)
{
Node *node = new Node(val);
if (index == 0) {
if (!head) {
head = node;
tail = head;
} else {
node->next = head;
head->prev = node;
head = node;
}
} else {
Node *prev = get_node(index - 1);
Node *next = prev->next;
prev->next = node;
node->prev = prev;
node->next = next;
if (next)
next->prev = node;
if (prev == tail)
tail = node;
}
}
};
int main()
{
LinkedList a;
a.append(1); // Appending elements to list
a.append(2);
a.append(3);
a.append(4);
a.append(5);
a.print(); // [1, 2, 3, 4, 5]
a.insert(3, 1);
a.print();
};
Output:
[1, 2, 3, 4, 5]
[1, 3, 2, 3, 4, 5]
Well the obvious problem in insert is that it calls get_node which tests the size member but nothing updates size anywhere.
However, fundamentally, your append function is wrong. It should be a class invariant that a linked list is either empty and has both its head and tail be nullptrs, or it should have a valid head and a valid tail.
Your append function does not enforce this invariant. It tries to work on two cases, one where the head is null and another where the tail is null. Ask yourself if those two cases are meaningful.
Rewrite append such that a list either is empty or has a valid head and tail.

Linked list in a class is not removing an element

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
struct Node
{
int x;
Node* next = nullptr;
};
typedef Node* nodeptr;
class L
{
private:
nodeptr head = nullptr;
int lengthCount = 0;
public:
void add(const int data);
void print();
void find(const int data);
void pop(const int data);
void listSize();
};
void L:: listSize()
{
cout << "The size of the link list is: " << lengthCount << endl;
}
void L::add(const int data)
{
lengthCount += 1;
Node* newNode = new Node;
newNode->x = data;
if(head == nullptr)
{
head = newNode;
}
else
{
nodeptr temp = head;
while(temp->next != nullptr)
{
temp = temp->next;
}
temp->next = newNode;
}
}
void L::pop(const int data)
{
if(head == nullptr)
{
cout << "Empty List" << endl;
}
else if(head->x == data)
{
head = head->next;
}
else
{
nodeptr temp = head->next;
while(temp != nullptr)
{
if(temp-> x != data)
{
temp = temp->next;
}
else
{
if(temp->next != nullptr)
{
temp = temp->next;
}
else
{
temp->next = nullptr;
}
break;
}
}
}
}
void L::find(const int data)
{
if(head == nullptr)
{
cout << "Empty List" << endl;
}
else
{
nodeptr temp = head;
for(temp; temp != nullptr; temp = temp->next)
{
if(temp->x == data)
{
cout << "Found" << endl;
break;
}
if(temp->next == nullptr)
cout << "Not Found" << endl;
}
}
}
void L::print()
{
nodeptr temp = head;
string line(20,'-');
cout << "Print list" << endl;
cout << line << endl;
while(temp != nullptr)
{
cout << temp->x << endl;
temp = temp->next;
}
cout << line << endl;
}
int main()
{
vector <int> val;
for(int i = 0; i < 10; i++)
val.push_back(5*i);
cout << "Printing list" << endl;
for(auto i : val)
cout << i << " ";
cout << endl;
L listObj;
cout << "Adding list" << endl;
for(auto i : val)
listObj.add(i);
listObj.print();
listObj.listSize();
listObj.find(15);
listObj.print();
cout << "popping 10" << endl;
listObj.pop(10);
listObj.print();
}
The problem that I am having is, I am not able to modify the actually memory of a linked list while using a class.
Im not sure what did I do wrong.
If adding works, i would say the idea of removing a value should work as well.
the remove function is called pop.
the pop function is not removing the value 10, so i am not sure why.
If it is a function that is not in a class, i would say i need to pass a head pointer with & operator then i can actually modify the value.
Please let me know where did I do wrong.
Thanks
Your pop method is not correct, You also have to link the current node with the previous next. It should be like this
void L::pop(const int data)
{
if(head == nullptr)
{
cout << "Empty List" << endl;
}
else if(head->x == data)
{
nodeptr temp = head;
head = head->next;
delete temp;
}
else
{
nodeptr temp = head->next;
nodeptr prev = head;
while(temp != nullptr)
{
if(temp-> x != data)
{
prev = temp;
temp = temp->next;
}
else
{
if(temp->next != nullptr)
{
prev -> next = temp -> next;
delete temp;
}
else
{
delete temp;
prev -> next = nullptr;
}
break;
}
}
}
}
You need to keep track of the "previous" node of the linked list somehow. There's many ways to do it, but the clearest might be:
void L::pop(const int data) {
if(head == nullptr) {
cout << "Empty List" << endl;
return;
}
if(head->x == data) {
node *temp = head;
head = head->next;
delete temp;
return;
}
int *prev = head;
int *temp = head->next;
while (temp != null) {
if (temp->x != data) {
prev = prev->next;
temp = temp->next;
} else {
prev->next = temp->next;
delete temp;
return;
}
}
}
In addition to the answers given already there's a variant without having to track the previous element all the time:
for(Node* tmp = head; tmp->next; tmp = tmp->next;)
{
if(tmp->next->x == data)
{
// OK, one intermediate pointer we need anyway, but we need it
// only once
Node* del = tmp->next;
tmp->next = tmp->next->next;
delete del;
break;
}
}
The for loop as a little bonus is a bit more compact, but that's just a matter of personal taste.

C++ XOR linked list, deleting data

I have to do XOR linked list. Now im at point that i want to proper way clear memory. I did something like this but it seems doesnt work.
Minimal code i could add to work
void deleteAll(Data* head)
{
if (head == NULL)
cout << "Empty list." << endl;
else
{
if (XOR(head, NULL) == NULL)
{
Data* tmp = NULL;
Data* next;
while (head)
{
next = XOR(head->npx, tmp);
tmp = head;
delete head;
//cout << head->liczba << endl; EDIT <<< this line is not problem
head = next;
}
}
}
}
This is the moment when i alocate data
Data* tmp = new Data;
tmp->liczba = num;
tmp->npx = XOR(*head, NULL);
if (*head != NULL)
{
(*head)->npx = XOR(XOR((*head)->npx,NULL),tmp);
}
*head = tmp;
tmp = NULL;
delete tmp;
In main function after deleting function i run printAll function, then i can see that data has not been cleared.
Edit:
#include <iostream>
using namespace std;
struct Data {
int liczba;
Data* npx;
};
struct Data* XOR(struct Data* prev, struct Data* next)
{
return (Data*)((uintptr_t)(prev) ^ (uintptr_t)(next));
}
void pushEnd(Data** head, int num)
{
Data* tmp = new Data;
tmp->liczba = num;
tmp->npx = XOR(*head, NULL);
if (*head != NULL)
{
(*head)->npx = XOR(XOR((*head)->npx,NULL),tmp);
}
*head = tmp;
tmp = NULL;
delete tmp;
}
void printBackward(Data* head)
{
if (head == NULL)
cout << "Pusta lista." << endl;
else
{
Data* next;
Data* prev = NULL;
while (head)
{
cout << head->liczba << endl;
next = XOR(head->npx, prev);
prev = head;
head = next;
}
}
}
void deleteAll(Data* head)
{
if (head == NULL)
cout << "Empty list." << endl;
else
{
if (XOR(head, NULL) == NULL)
{
Data* tmp = NULL;
Data* next;
while (head)
{
next = XOR(head->npx, tmp);
tmp = head;
delete head;
head = next;
}
}
}
}
int main()
{
Data* head = NULL;
pushEnd(&head, 5);
pushEnd(&head, 10);
pushEnd(&head, 7);
pushEnd(&head, 3);
printBackward(head);
cout << head->liczba;
cout <<endl<< "DEL" << endl;
deleteAll(head);
printBackward(head);
}
In deleteAll you have a line preventing all deletions:
if(XOR(head, NULL) == NULL) { // remove this line
Your deleteAll functions also takes a Data* and all changes you make to head will be local to the function only. A minimal change needed that should make it work is to take head as a Data*& - that is, a reference to a pointer, so that all changes to do to head in your function are actually made to the head you defined in main.
Example:
void deleteAll(Data*& head) {
if(head == nullptr)
cout << "Empty list." << endl;
else {
Data* tmp = nullptr;
Data* next;
while(head) {
next = XOR(head->npx, tmp);
tmp = head;
delete head;
head = next;
}
}
}
You still call it the same way: deleteAll(head);.
If you prefer calling it with deleteAll(&head); you could define the function like this:
void deleteAll(Data** head) {
if(*head == nullptr)
cout << "Empty list." << endl;
else {
Data* tmp = nullptr;
Data* next;
while(*head) {
next = XOR((*head)->npx, tmp);
tmp = *head;
delete *head;
*head = next;
}
}
}

Expection Unhandled Error when implementing a LinkedList in c++

Alright so I am attempting to implement a LinkedList data structure but when I try to loop through my list (printNodes and insert functions) I run into an error that says: "Unhandled exception thrown: read access violation. tmpNode was 0xCDCDCDCD." I feel like it has something to do with my pointers not behaving in the manner I think they should but I am not sure. Some assistance would be very much appreciated.
#include<iostream>;
using namespace std;
struct Node {
int data;
Node* next;
Node(int el) {data = el; } //constructor
Node(int el, Node* ptr) { data = el; next = ptr; } //constructor
};
class LinkedList {
public:
Node* head = NULL, * tail = NULL;
void addToHead(int el) {
head = new Node(el, head);
}
void insert(int el) {
Node* newNode = new Node(el);
if (head == nullptr) {
head = newNode;
}
else {
Node* tmpNode = head;
while (tmpNode->next != nullptr) {
tmpNode = tmpNode->next;
}tmpNode->next = newNode;
}
}
void printNodes() {
Node* tmpNode = head;
cout << tmpNode->data;
while (tmpNode->next != nullptr) {
std::cout << tmpNode->data;
tmpNode = tmpNode->next;
}
}
};
int main() {
LinkedList myList = LinkedList();
myList.insert(10);
myList.addToHead(20);
myList.insert(10);
myList.printNodes();
}
Your iteration is correct, but there is a problem with your printNodes function. It dereference tmpNode without checking for null:
void printNodes() {
Node* tmpNode = head;
cout << tmpNode->data; // <-- here
while (tmpNode->next != nullptr) {
std::cout << tmpNode->data;
tmpNode = tmpNode->next;
}
}
I would change it to the following:
void printNodes() {
Node* tmpNode = head;
while (tmpNode != nullptr) {
std::cout << tmpNode->data << ", ";
tmpNode = tmpNode->next;
}
}
Apart from that, as said in comments, if you set next member to null in Node constructor it should work fine.
To search, it is the same thing but checking for the data:
Node* findNode(int el) {
Node* tmpNode = head;
Node* ret = nullptr;
while (tmpNode != nullptr) {
if (tmpNode->data == el) {
ret = tmpNode;
break;
}
tmpNode = tmpNode->next;
}
return ret;
}
And in main:
Node* n = myList.findNode(10);
if (n)
std::cout << "N 10: " << n->data << "\n";
n = myList.findNode(30);
if (n)
std::cout << "N 30: " << n->data << "\n";
else
std::cout << "There is no N 30\n";
There are memory leak problems also, as specified by #RikusHoney in the comments.

modify the linked list main function code in which user will input the index and data of the node with proper messages

I have a link list in which user will input the index and data of the node with proper messages....
it is a very simple task i know but i am so confuse how to do it .
all i want is that you edit my code so that user can enter which index he/she want to enter data and also he/she is able to enter his/her data..
I'll be very great full if some one reply .
#include <iostream>
using namespace std;
class Node {
public:
double data; // data
Node* next; // pointer to next
};
class List {
public:
List(void) { head = NULL; } // constructor
~List(void); // destructor
bool IsEmpty() { return head == NULL; }
Node* InsertNode(int index, double x);
int FindNode(double x);
int DeleteNode(double x);
void DisplayList(void);
private:
Node* head;
};
Node* List::InsertNode(int index, double x)
{
if (index < 0)
return NULL;
int currIndex = 1;
Node* currNode = head;
while (currNode && index > currIndex) {
//Try to locate index'th node. If it doesn't exist, return NULL
currNode = currNode->next;
currIndex++;
}
if (index > 0 && currNode == NULL)
return NULL;
Node* newNode = new Node;
newNode->data = x;
if (index == 0) {
newNode->next = head;
head = newNode;
}
else {
newNode->next = currNode->next;
currNode->next = newNode;
}
return newNode;
}
int List::FindNode(double x)
{
Node* currNode = head;
int currIndex = 1;
while (currNode && currNode->data != x) {
currNode = currNode->next;
currIndex++;
}
if (currNode)
return currIndex;
return 0;
}
int List::DeleteNode(double x)
{
Node* prevNode = NULL;
Node* currNode = head;
int currIndex = 1;
while (currNode && currNode->data != x) {
prevNode = currNode;
currNode = currNode->next;
currIndex++;
}
if (currNode) {
if (prevNode) {
prevNode->next = currNode->next;
delete currNode;
}
else {
head = currNode->next;
delete currNode;
}
return currIndex;
}
return 0;
}
void List::DisplayList()
{
int num = 0;
Node* currNode = head;
while (currNode != NULL) {
cout << currNode->data << endl;
currNode = currNode->next;
num++;
}
cout << "Number of nodes in the list: " << num << endl;
}
List::~List(void)
{
Node* currNode = head;
Node* nextNode = NULL;
while (currNode != NULL) {
nextNode = currNode->next;
delete currNode; // destroy the current node
currNode = nextNode;
}
}
int main(void)
{
List list;
list.InsertNode(0, 7.0); // successful
list.InsertNode(1, 5.0); // successful
list.InsertNode(-1, 5.0); // unsuccessful
list.InsertNode(0, 6.0); // successful
list.InsertNode(8, 4.0); // unsuccessful
// print all the elements
list.DisplayList();
if (list.FindNode(5.0) > 0)
cout << "5.0 found" << endl;
else
cout << "5.0 not found" << endl;
if (list.FindNode(4.5) > 0)
cout << "4.5 found" << endl;
else
cout << "4.5 not found" << endl;
list.DeleteNode(7.0);
list.DisplayList();
return 0;
}
Just read in the input and call the method on the list object. What did you find so confusing about it?
Also, try to get out of the habit of using namespace std! Append this code to the main function.
int index;
double data;
std::cout << "Enter the index: ";
std::cin >> index;
std::cout << "Enter data: ";
std::cin >> data;
list.InsertNode(index, data);
list.DisplayList();
Declare temporary variables index and data to hold the input from the console.
Print to the console asking the user to enter the index and data using std::cout , which is at the position at which the node is to be entered. std::cin can be used to read input from the console and store it in a variable
The nodes of your linked list contain a data field of type double which is the actual data of your linked list. Using your list object, you call the InsertNode() method along with this index and data.
Don't worry it a very simple task
1:- firstly you should give values in particulate index
2:- ten just fetch it from the particular index
for further information you can contact