Segmentation fault while implementing linkedlists in c++ - c++

I am currently learning data structures, I was trying to create a function insert to insert a node at the nth position but I am always getting a segmentation error could you please help.
#include <iostream>
using namespace std;
struct node {
int data;
node* next;
};
struct node* head = NULL;
void insert(int dat, int pos) {
node* temp = new node;
temp->data = dat;
temp->next = NULL;
if (pos == 1) {
temp->next = head;
head = temp;
return;
}
node* newtemp = head;
for (int i = 0; i <= pos - 1; i++) {
newtemp = newtemp->next;
}
temp->next = newtemp->next;
newtemp->next = temp;
}
void print() {
node* temp = head;
while (temp != NULL) {
cout << temp->data;
temp = temp->next;
}
cout << endl;
}
int main() {
head = NULL;
insert(4, 1);
insert(6, 2);
print();
}

It should be
i<pos-1
temp->next=newtemp->next;
newtemp->next=temp;
And you should check if the Linkedlist have the position you have given
ie, if you pass to add node in 6th position to a Linkedlist having 2 nodes, it will give you segmentation fault.
By NULL->next
So you should check whether the linked list have the length less than or equal to position.
flag=false;
while(temp!=NULL)
{
if(i==Pos){
flag=true;
break;
}
temp=temp->next;
i++;
}
if flag is false then length is insufficient else do your stuff in temp

Look at this statement of insert() function:
for (int i = 0; i <= pos - 1; i++) {
For inserting element 6, you are giving positing 2.
First iteration:
initialize i with 0
0 <= 2 - 1 ==> true
newtemp = newtemp->next
[After this statement, newtemp is NULL because your linked list has only one element]
i++ ==> i is now 1
Second iteration
1 <= 2 - 1 ===> true
newtemp = newtemp->next
[newtemp is NULL and this statment will attempt to access next of a NULL
which is resulting in segmentation fault]
I hope you understood the cause of segmentation fault and a simple change can solve this problem - add NULL check for newtemp node, like this
for (int i = 0; i < pos && newtemp->next != NULL; i++) {
Your code does not check the validity of a pos value passed and with your current implementation it will add the element at the end of list if the pos value is greater than size of linked list. May you want to throw error when the value of pos is not valid. Also, you are not releasing the memory allocated for linked list nodes. Follow the good programming practice - release allocated memory before program exit.
Additional:
Since you are implementating the linked list in c++, you should use the object oriented concepts in you implementation. For e.g. bundle the data and functions operate on that data in one unit:
class Node {
private:
int data;
Node* next;
public:
// Add constructor for initialization of memeber variables
// Add destructor for cleanup and release memory
void insert(int dat, int pos);
void print();
};
A better implementation would be to separate the node and linkedlist in two different classes and bind their data with respective operations in them. For e.g.
class Node {
private:
int data;
Node* next;
public:
Node();
Node(const int& val);
void setData(const int& val);
int getData() const;
void setNext(Node* const nodePtr);
Node* getNext() const;
};
Singly linked list class LinkedList consisting of Node objects:
class LinkedList {
private:
Node* headNode;
Node* tailNode;
Node* currNode;
unsigned int count;
public:
LinkedList(); // constructor
// other overload of constructor, copy constructor, assignment operator, move semantics ....
~LinkedList(); // destructor
bool insertNode(const Node& newNode);
// other overload of insert, like insert at given position, at head of list, at tail of list etc..
unsigned int getCount() const;
Node* getHeadNode() const;
Node* getCurrNode() const;
Node* getTailNode() const;
bool deleteNode(const Node& node);
// other overload of delete node like detete tail node, delete head node etc.
bool deleteList();
};

Related

C++ - How to subtract two Linked Lists from one another?

I am trying to make a way to take two Linked List objects (doubly-linked), say LL1 and LL2, and remove the 'overlapping' elements within LL1 which also appear in LL2.
So for example if:
LL1 = {1,2,3};
LL2 = {9,2,8};
I want an output of:
LL1 = {1,3};
I am trying to do this via overloading the '-=' operator to work with two linked list objects. It compiles fine, but I'm getting a 'segmentation fault (core dumped)' error during runtime at the '-=' operator call. Not sure why. Below is my code. Any help would be appreciated, thankyou kindly.
Node.h:
// Node.h
/*******************************/
// Last Updated: Tues Aug 31 2021
// Program Description: Header file for Node
#ifndef NODE_H
#define NODE_H
#include <iostream>
#include <cstdlib>
#include "EToll.h"
using namespace std;
class Node {
public:
typedef EToll value_type; //typedef - now value_type is synonym for EToll object
//Constructors:
Node(); //default
Node(value_type&); //constructor with 1 arg - data item
Node(const value_type& i, Node* n, Node* p); //specific constructor with 3 arguments
//Destructor:
~Node();
//mutators (setters):
void set_next(Node*);
void set_prev(Node*);
void set_data(const value_type&);
//accessors (getters):
Node* get_next() const;
Node* get_prev() const;
value_type& get_data();
private:
Node* next; //ptr to next (or NULL)
Node* prev; //ptr to prev (or NULL)
value_type data; //the payload
};
#endif
Node.cpp:
// Node.cpp
/*******************************/
// Last Updated: Tues Aug 31 2021
// Program Description: Implementation of Node
#include "Node.h"
#include <cstdlib>
//Constructors:
Node::Node() //default constructor
{
data = value_type(); //creates an empty EToll object, since value_type is a synonym for EToll
next = NULL;
prev = NULL;
}
Node::Node(value_type& item) //constructor with 1 argument - a data item
{
data = item;
next = NULL;
prev = NULL;
}
Node::Node(const value_type& i, Node* n, Node* p) //constructor with 3 arguments
{
data = i;
next = n;
prev = p;
}
//Empty destructor:
Node::~Node(){}
//Mutators (setters):
void Node::set_next(Node* next_ptr) {next = next_ptr;}
void Node::set_prev(Node* prev_ptr) {prev = prev_ptr;}
void Node::set_data(const value_type& new_data) {data = new_data;}
//Accessors (getters):
Node* Node::get_next() const {return next;}
Node* Node::get_prev() const {return prev;}
/* Note that get_data() has Node::value_type& instead of value_type& as it's return type as the
compiler doesn't check if the return type of a function is part of a member function, and thus
it doesn't look in Node for a value_type. A more detailed explanation can be found at: https://stackoverflow.com/questions/68991650/error-value-type-does-not-name-a-type-in-c */
Node::value_type& Node::get_data() {return data;}
LinkedList.h:
// LinkedList.h
/*******************************/
// Last Updated: Tues Aug 31 2021
// Program Description: Header file for LinkedList
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "Node.h"
#include <iostream>
#include <cstdlib>
#include <string>
class LinkedList
{
public:
typedef Node::value_type value_type;
//Constructor:
LinkedList();
//Destructor:
~LinkedList();
//Insert function:
//void insert(value_type& item);
//length function:
int length();
//count function:
int count(string);
//totalIncome function:
double totalIncome();
//addTo functions:
void addToHead(value_type&);
void addToTail(value_type&);
//accessors (getters):
value_type& getHead();
Node* getHeadAdd();
value_type& getTail();
//remove functions:
void removeFromHead();
void removeFromTail();
void remove(string);
void removeByNode(Node* c); //remove a particular node
//search funciton:
//Preconditions: None
//Postconditions: Current points to the first Node storing the target, and true is returned. If not present, current is NULL and false is returned
bool search(const value_type& target);
//concatenation operator (+=) overload:
//Preconditions: LL1 and LL2 are instances of LinkedList
//Postconditions: Each Node of LL2 is traversed. At each individual Node, itis appended to LL1
LinkedList operator += (const LinkedList& LL2);
//remove overlap operator (-=) overload:
//Preconditions: LL1 and LL2 are instances of LinkedList
//Postconditions: Each Node of LL2 is traversed. At each individual Node, it's match is searched for within LL1. If a match is found, the matching Node in LL1 is deleted and the next node in LL2 is traversed
LinkedList operator -= (const LinkedList& LL2);
//NEED A .COUNT FUNCTION!!
private:
Node* head;
Node* tail;
Node* current;
};
//stream insertion operator (<<) overload:
//Preconditions: LinkedList obj "LL" exists and we wish to output it
//Postconditions: LL exists without change
ostream& operator << (ostream& out, LinkedList& LL);
#endif
LinkedList.cpp:
// LinkedList.cpp
/*******************************/
// Last Updated: Wed Aug 31 2021
// Program Description: Implementation of LinkedList
#include "LinkedList.h"
#include <cstdlib>
//Constructors:
LinkedList::LinkedList() //default constructor
{
head = NULL;
tail = NULL;
current = NULL;
}
//Empty destructor:
LinkedList::~LinkedList(){}
//length() function:
//Preconditions: None
//Postconditions: A count of the nodes is returned (ie no of nodes in the LinkedList)
int LinkedList::length()
{
int answer = 0;
for (current = head; current != NULL; current = current->get_next())
{
answer++;
}
return answer;
}
//count function:
int LinkedList::count(string type)
{
int returnCount = 0;
//cycle through LinkedList:
for (current = head; current != NULL; current = current->get_next())
{
//check for match:
if (type == current->get_data().get_type())
{
//increment the counter
returnCount++;
}
}
return returnCount;
}
//totalIncome function:
double LinkedList::totalIncome()
{
double returnTotal = 0;
//cycle through LinkedList:
for (current = head; current != NULL; current = current->get_next())
{
returnTotal = returnTotal + current->get_data().get_charge();
}
return returnTotal;
}
//addToHead function:
//Preconditions: None
//Postconditions: A new node storing the supplied item is created and linked in to be list's new head
void LinkedList::addToHead(Node::value_type& item)
{
Node* newNode = new Node(item);
//Check if the list is empty:
if (length() == 0)
{ //list is empty, so:
head = newNode;
tail = newNode;
} else
{ //list is not empty, so:
head->set_prev(newNode);
newNode->set_next(head);
head = newNode;
}
/*
head = new Node(item, head, NULL);
//In case the list is empty:
if (tail == NULL)
{
tail = head;
}
*/
}
//addToTail function:
//Preconditions: None
//Postconditions: A new node storing the supplied item is created and linked in to be list's new tail
void LinkedList::addToTail(Node::value_type& item)
{
Node* newNode = new Node(item);
//Check if the list is empty:
if (length() == 0)
{ //list is empty, so:
head = newNode;
tail = newNode;
} else
{ //list is not empty, so:
tail->set_next(newNode);
newNode->set_prev(tail);
tail = newNode;
}
}
//getHead function:
Node::value_type& LinkedList::getHead()
{
return head->get_data();
}
//getHeadAdd function:
Node* LinkedList::getHeadAdd()
{
return head->get_next()->get_prev();
}
//getTail function:
Node::value_type& LinkedList::getTail()
{
return tail->get_data();
}
//removeFromHead function:
void LinkedList::removeFromHead()
{
Node* temp;
temp = head->get_next();
if (head != NULL)
{
temp->set_prev(NULL);
head = temp;
} else
{ //list is empty, so update the tail
tail = NULL;
}
}
//removeFromTail function:
void LinkedList::removeFromTail()
{
Node* temp;
temp = tail->get_prev();
if (head != NULL)
{
temp->set_next(NULL);
tail = temp;
} else
{ //list is empty, so update the head
head = NULL;
}
}
//remove function: removes a Node by a string input
void LinkedList::remove(string l)
{
//cycle through LinkedList:
for (current = head; current != NULL; current = current->get_next())
{
//check for match:
if (l == current->get_data().get_licence() && current == head)
{
removeFromHead();
} else if (l == current->get_data().get_licence() && current == tail)
{
removeFromTail();
} else if (l == current->get_data().get_licence())
{
//delete the node
removeByNode(current);
} else
{
//do nothing, move on to next iteration of for loop
}
}
}
//removeByNode function:
//Preconditions: input c points to a node to be removed
//Postconditions: the node pointed to by c before is now gone. current now points to head
void LinkedList::removeByNode(Node* c)
{
current = c;
current->get_prev()->set_next(current->get_next());
current->get_next()->set_prev(current->get_prev());
delete current;
current = head;
}
//search function:
bool LinkedList::search(const Node::value_type& target)
{
for (current = head; current != NULL; current = current->get_next())
{
if (target == current->get_data())
{
return true;
}
}
//else:
return false;
}
// += operator overload (new):
LinkedList LinkedList::operator += (const LinkedList& LL2)
{
LinkedList* t = this;
Node* temp = LL2.head;
while (temp != NULL)
{
t->addToTail(temp->get_data());
temp = temp->get_next();
}
return *t;
}
// -= operator overload:
LinkedList LinkedList::operator -= (const LinkedList& LL2)
{
LinkedList* t = this;
Node* temp1;
Node* temp2;
//Cycle through LL2:
for (temp2 = LL2.head; temp2 != NULL; temp2 = temp2->get_next())
{
//Cycle through LL1:
for (temp1 = t->head; temp1 != NULL; temp1 = temp1->get_next())
{
//Check if current of LL1 has a match in LL2:
if (temp1->get_data() == temp2->get_data())
{
t->removeByNode(temp1);
}
}
}
return *t;
}
-= operator overload (within LinkedList.cpp, just putting it here under new heading for easy location):
// -= operator overload:
LinkedList LinkedList::operator -= (const LinkedList& LL2)
{
LinkedList* t = this;
Node* temp1;
Node* temp2;
//Cycle through LL2:
for (temp2 = LL2.head; temp2 != NULL; temp2 = temp2->get_next())
{
//Cycle through LL1:
for (temp1 = t->head; temp1 != NULL; temp1 = temp1->get_next())
{
//Check if current of LL1 has a match in LL2:
if (temp1->get_data() == temp2->get_data())
{
t->removeByNode(temp1);
}
}
}
return *t;
}
-= operator call within another 'main()' program:
LinkedList tollBooth1;
LinkedList tollBooth2;
LinkedList dailyReport;
//(add data to tollBooth 1 and 2, merge these 2 objects into dailyReport)
//removing the contents of both booths from daily report:
dailyReport -= tollBooth1;
dailyReport -= tollBooth2;
You've included way too much code. The general ask on this site is to provide a minimal reproducible example.
Problems
I have no idea why you have a member variable named current. It often points to deleted memory.
You need to implement the "rule of three" or the "rule of five" on your LinkedList class. If you copy the LinkedList, and then modify it, you will have dangling pointers.
LinkedList a;
LinkedList b = a;
a.RemoveHead();
// b.head is now pointing to deleted memory.
LinkedList::removeByNode(Node* c) does not update the head and tail member variables if the removed node was the head or tail respectively.
Your operator-= uses temp1 after it has been deleted.
There are likely more issues.

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.

Trouble removing from linked list in C++

I have a function that removes from a linked list. Each node in the linked list is a dynamically created struct. To remove, I pass a data value in that I would like to search for in the list of nodes. If one of those nodes contains that data, I want to remove the entire node containing that data. It appears like they get added fine, but whenever I remove, the size variable decrements but the nodes are still in the list.
In Mag.h:
struct ListNode
{
int* data;
ListNode* nextNode;
};
class Mag
{
private:
ListNode* head;
public:
Mag();
Mag(Mag& mag);
Mag &operator= (const Mag &);
~Mag();
int size;
void add(const int&);
void remove(const int&);
void printList();
};
}
I add nodes to the list like this:
// adds to front of list
void Mag::add(int const &num)
{
Node* new_data = new ListNode();
new_data->data = num;
new_data->next = head;
head = newNode;
size++;
}
Now here's how I remove them (probably the issue):
void Mag::remove(int const &num)
{
if (head == NULL)
return;
int look_for = num;
ListNode* searchFor = head;
int count = 0;
count = size;
if (count != 0)
{
do
{
if (searchFor->data == look_for)
{
ListNode* delete_node = new ListNode;
delete_node = searchFor;
searchFor = searchFor->next;
size--;
delete delete_node;
return;
}
searchFor = searchFor->next;
count--;
} while (count != 0);
}
}

Implementing a double linked list in C++, pointers and odd values

I'm pretty rusty in C++ and I'm trying to implement a double linked list but I am having some reading violations and having some odd values being given.
#include <iostream>
struct Node
{
int val;
Node* next;
Node* prev;
};
class linkedList
{
public:
linkedList(); //constructor
~linkedList(); //destructor
void push_back(int x);
void addtofront(int x);
//void deleteNode(int x);
bool isempty();
void firstelem();
void prnt_tail();
/*void insert_after(int x, int y);
void insert_before(int x, int y);*/
private:
Node* head;
Node* next;
Node* prev;
};
linkedList::linkedList(){};
linkedList::~linkedList(){};
void linkedList::push_back(int x)
{
linkedList* list = this;
Node temp;
temp.val=x;
temp.next=NULL;
temp.prev=NULL;
if (!head)
{
linkedList* list = new linkedList();
list->head;
head = new Node;
head->val = x;
head->next = NULL;
head->prev = NULL;
}
else
{
Node* temp1;
temp1=head;
while (temp1->next!=NULL)
{
temp1 = temp1->next;
}
temp.next= NULL;
temp.prev=temp1;
temp.val = x;
}
};
void linkedList::addtofront(int x)
{
linkedList* list = this;
Node temp;
temp.val=x;
temp.next=NULL;
temp.prev=NULL;
if (!head)
{
linkedList* list = new linkedList();
list->head;
head = new Node;
head->val = x;
head->next = NULL;
head->prev = NULL;
}
else
{
list->head->prev=&temp;
temp.next=head;
head=&temp;
}
};
//void linkedList::deleteNode(int x)
//{
// if(head)
// {
// linkedList *ptr = head;
// while(ptr->node.val != x)
// {
// ptr = ptr->node.next;
// }
// (ptr->node.next)->prev=ptr->node.prev;
// ptr->node.prev=ptr->node.next;
// delete ptr;
// }
// else
// std::cout<<"empty list";
//}
bool linkedList::isempty()
{
if(head)
return false;
else return true;
};
void linkedList::firstelem()
{
std::cout<<head->val;
};
void linkedList::prnt_tail()
{
if(head)
{
Node *temp;
temp=head;
temp=head->next;
std::cout<<temp;
while(temp->next!=NULL)
{
std::cout<<temp->val<<" ";
}
std::cout<<temp->val;
}
else
{
std::cout<<"empty list";
}
};
//linkedList::insert_after(int x, int y)
//{
//
//}
//
//linkedList::insert_before(int x, int y)
//{
//
//}
and my main
#include "linkedlist2.h"
#include <stdlib.h>
#include <iostream>
int main()
{
linkedList example;
if(example.isempty())
std::cout<<"this list is empty "<<"\n";
else
std::cout<<"this list is not empty"<<"\n";
for (int i = 1; i<=20; i++)
{
example.push_back(i);
//example.prnt_tail();
}
example.addtofront(25);
example.firstelem();
std::cout<<"\n";
example.addtofront(28);
example.firstelem();
std::cout<<"\n";
if(example.isempty())
std::cout<<"this list is empty "<<"\n";
else
std::cout<<"this list is not empty"<<"\n";
//example.push_back(26);
//std::cout<<example.head->next->val;
example.firstelem();
std::cout<<"\n";
example.prnt_tail();
std::cout<<"\n";
system("pause");
}
when I run main I get
this list is empty
-858993460
-858993460
this list is not empty
-858993460
CCCCCCCC
I also get the error
Access violation reading location 0xCCCCCCD0.
and the next statement to be executed is the while loop in "void linkedList::prnt_tail()"
I'm fairly sure my problem is in my pointers and all that. Like I said, I'm really rusty so any help you can give would be greatly appreciated, even in things not directly related to my problems.
So, there's a lot of problems in this code. Let's see what we can do:
It's odd that you have next and prev members in both your node objects and your linkedList objects. Let's fix this by making the linkedList object point to the first node (that is, the head node), and then use the members in each node to point to the next object.
This means that we have:
struct Node {
int val;
struct Node* next;
struct Node* prev;
};
class linkedList {
public:
linkedList(); //constructor
~linkedList(); //destructor
void push_back(int x);
void addtofront(int x);
bool isempty();
private:
Node* head;
};
Let's fix a number of errors in your push_back. First, no matter what the state of the linkedList is, we need to create a new Node on the heap, and then we will be placing that Node somewhere in the linkedList.
void linkedList::push_back(int x)
{
Node *node = new Node;
node->next = NULL;
node->prev = NULL;
node->val = x;
if (head == NULL) {
head = node;
} else {
Node *last = head;
while (last->next != NULL)
last = last->next;
last->next = node;
node->prev = last;
}
}
We also need to fix push_front. This code should look somewhat similar to push_back.
void linkedList::addtofront(int x)
{
Node *node = new Node;
node->next = NULL;
node->prev = NULL;
node->val = x;
if (head == NULL) {
head = node;
} else {
node->next = head;
head->prev = node;
head = node;
}
}
If you're going to write a constructor, you probably should do that correctly:
linkedList() {
head = NULL;
}
It's also worth noting that you will want a real destructor to clean up all of these objects that you are creating on the heap. And then you also need to implement the copy constructor and assignment operator.
Apart from a extra useless semicolon, this looks wrong:
linkedList::linkedList(){};
A constructor is supposed to provide initial values for members, and you haven't done so. Leaving pointer members uninitialized is very bad style, and is the cause of many of your problems.
Because these members aren't initialized, when you later read from them (e.g. isEmpty()'s test if (head)) it will be undefined behavior.
To start with, in addToFront and push_back you probably do not want to be creating new linked lists on the heap. You already have a linked list (the one the method is currently being run on) which you want to modify. Don't create new linked lists here.
However, you DO want to create new Nodes on the heap, never on the stack. In at least one place you create a node on the stack, eg
Node temp;
And then later store and use a pointer to that object. As soon as the function quits, that variable is gone and that pointer is pointing to garbage.
in linked list class , (Node* next;) and (Node* prev;) are extera

C++ Linked List assignment: trouble with insertion and deletion

I am working on a linked list implementation in C++. I am making progress but am having trouble getting the insertion functionality and deletion functionality to work correctly. Below is list object in the C++ header file:
#ifndef linkList_H
#define linkList_h
//
// Create an object to represent a Node in the linked list object
// (For now, the objects to be put in the list will be integers)
//
struct Node
{
Node() : sentinel(0) {}
int number;
Node* next;
Node* prev;
Node* sentinel;
};
//
// Create an object to keep track of all parts in the list
//
class List
{
public:
//
// Contstructor intializes all member data
//
List() : m_listSize(0), m_listHead(0) {}
//
// methods to return size of list and list head
//
Node* getListHead() const { return m_listHead; }
unsigned getListSize() const { return m_listSize; }
//
// method for adding and inserting a new node to the linked list,
// retrieving and deleting a specified node in the list
//
void addNode(int num);
void insertNode(Node* current);
void deleteNode(Node* current);
Node* retrieveNode(unsigned position);
private:
//
// member data consists of an unsigned integer representing
// the list size and a pointer to a Node object representing head
//
Node* m_listHead;
unsigned m_listSize;
};
#endif
And here is the implementation (.cpp) file:
#include "linkList.h"
#include <iostream>
using namespace std;
//
// Adds a new node to the linked list
//
void List::addNode(int num)
{
Node *newNode = new Node;
newNode->number = num;
newNode->next = m_listHead;
m_listHead = newNode;
++m_listSize;
}
//
// NOTWORKING: Inserts a node which has already been set to front
// of the list
//
void List::insertNode(Node* current)
{
// check to see if current node already at
// head of list
if(current == m_listHead)
return;
current->next = m_listHead;
if(m_listHead != 0)
m_listHead->prev = current;
m_listHead = current;
current->prev = 0;
}
//
// NOTWORKING: Deletes a node from a specified position in linked list
//
void List::deleteNode(Node* current)
{
current->prev->next = current->next;
current->next->prev = current->prev;
}
//
// Retrieves a specified node from the list
//
Node* List::retrieveNode(unsigned position)
{
if(position > (m_listSize-1) || position < 0)
{
cout << "Can't access node; out of list bounds";
cout << endl;
cout << endl;
exit(EXIT_FAILURE);
}
Node* current = m_listHead;
unsigned pos = 0;
while(current != 0 && pos != position)
{
current = current->next;
++pos;
}
return current;
}
After running a brief test program in the client C++ code, here is the resulting output:
Number of nodes: 10
Elements in each node:
9 8 7 6 5 4 3 2 1 0
Insertion of node 5 at the list head:
4 9 8 7 6 5 4 9 8 7
Deletion of node 5 from the linked list
As you can see, the insertion is not simply moving node 5 to head of list, but is overwriting other nodes beginning at the third position. The pseudo code I tried to implement came from the MIT algorithms book:
LIST-INSERT(L, x)
next[x] <- head[L]
if head[L] != NIL
then prev[head[L]] <- x
head[L] <- x
prev[x] <- NIL
Also the deletion implementation is just crashing when the method is called. Not sure why; but here is the corresponding pseudo-code:
LIST-DELET'
next[prev[x]] <- next[x]
prev[next[x]] <- prev[x]
To be honest, I am not sure how the previous, next and sentinel pointers are actually working in memory. I know what they should be doing in a practical sense, but looking at the debugger it appears these pointers are not pointing to anything in the case of deletion:
(*current).prev 0xcdcdcdcd {number=??? next=??? prev=??? ...} Node *
number CXX0030: Error: expression cannot be evaluated
next CXX0030: Error: expression cannot be evaluated
prev CXX0030: Error: expression cannot be evaluated
sentinel CXX0030: Error: expression cannot be evaluated
Any help would be greatly appreciated!!
You have got an error in addNode(). Until you fix that, you can't expect insertNode to work.
Also, I think your design is quite silly. For example a method named "insertNode" should insert a new item at arbitrary position, but your method insertNode does a pretty different thing, so you should rename it. Also addNode should be renamed. Also as glowcoder wrote, why are there so many sentinels? I am affraid your class design is bad as a whole.
The actual error is that you forgot to set prev attribute of the old head. It should point to the new head.
void List::addNode(int num)
{
Node *newNode = new Node;
newNode->number = num;
newNode->next = m_listHead;
if(m_listHead) m_listHead->prev = newNode;
m_listHead = newNode;
++m_listSize;
}
Similarly, you have got another error in deleteNode(). It doesn't work when deleting last item from list.
void List::deleteNode(Node* current)
{
m_listSize--;
if(current == m_listHead) m_listHead = current->next;
if(current->prev) current->prev->next = current->next;
if(current->next) current->next->prev = current->prev;
}
Now you can fix your so-called insertNode:
void List::insertNode(Node* current)
{
int value = current->number;
deleteNode(current);
addNode(value);
}
Please note that I wrote everything here without compiling and testing in C++ compiler. Maybe there are some bugs, but still I hope it helps you at least a little bit.
In deleteNode, you are not handling the cases where current->next and/or current->prev is null. Also, you are not updating the list head if current happens to be the head.
You should do something like this:
node* next=current->next;
node* prev=current->prev;
if (next!=null) next->prev=prev;
if (prev!=null) prev->next=next;
if (m_listhead==current) m_list_head=next;
(Warning: I have not actually tested the code above - but I think it illustrates my idea well enough)
I am not sure what exactly your InsertNode method does, so I can't offer any help there.
OK.
As #Al Kepp points out, your "add node" is buggy. Look at Al's code and fix that.
The "insert" that you are doing does not appear to be a normal list insert. Rather it seems to be a "move to the front" operation.
Notwithstanding that, you need to delete the node from its current place in the list before you add it to the beginning of the list.
Update
I think you have misunderstood how insert should work. It should insert a new node, not one that is already in the list.
See below for a bare-bones example.
#include <iostream>
// List Node Object
//
struct Node
{
Node(int n=0);
int nData;
Node* pPrev;
Node* pNext;
};
Node::Node(int n)
: nData(n)
, pPrev(NULL)
, pNext(NULL)
{
}
//
// List object
//
class CList
{
public:
//
// Contstructor
//
CList();
//
// methods to inspect list
//
Node* Head() const;
unsigned Size() const;
Node* Get(unsigned nPos) const;
void Print(std::ostream &os=std::cout) const;
//
// methods to modify list
//
void Insert(int nData);
void Insert(Node *pNew);
void Delete(unsigned nPos);
void Delete(Node *pDel);
private:
//
// Internal data
//
Node* m_pHead;
unsigned m_nSize;
};
/////////////////////////////////////////////////////////////////////////////////
CList::CList()
: m_pHead(NULL)
, m_nSize(0)
{
}
Node *CList::Head() const
{
return m_pHead;
}
unsigned CList::Size() const
{
return m_nSize;
}
void CList::Insert(int nData)
{
Insert(new Node(nData));
}
void CList::Insert(Node *pNew)
{
pNew->pNext = m_pHead;
if (m_pHead)
m_pHead->pPrev = pNew;
pNew->pPrev = NULL;
m_pHead = pNew;
++m_nSize;
}
void CList::Delete(unsigned nPos)
{
Delete(Get(nPos));
}
void CList::Delete(Node *pDel)
{
if (pDel == m_pHead)
{
// delete first
m_pHead = pDel->pNext;
if (m_pHead)
m_pHead->pPrev = NULL;
}
else
{
// delete subsequent
pDel->pPrev->pNext = pDel->pNext;
if (pDel->pNext)
pDel->pNext->pPrev = pDel->pPrev;
}
delete pDel;
--m_nSize;
}
Node* CList::Get(unsigned nPos) const
{
unsigned nCount(0);
for (Node *p=m_pHead; p; p = p->pNext)
if (nCount++ == nPos)
return p;
throw std::out_of_range("No such node");
}
void CList::Print(std::ostream &os) const
{
const char szArrow[] = " --> ";
os << szArrow;
for (Node *p=m_pHead; p; p = p->pNext)
os << p->nData << szArrow;
os << "NIL\n";
}
int main()
{
CList l;
l.Print();
for (int i=0; i<10; i++)
l.Insert((i+1)*10);
l.Print();
l.Delete(3);
l.Delete(7);
l.Print();
try
{
l.Delete(33);
}
catch(std::exception &e)
{
std::cerr << "Failed to delete 33: " << e.what() << '\n';
}
l.Print();
return 0;
}