.exe has triggered a breakpoint and exception thrown everywhere - c++

hope you're all doing well
im working on an assignment and i've been stuck here at this point for ages, and there are no errors or warnings in my code i dunno whats wrong. I'd appreciate the help
i checked all the pointers and null related things and still i couldnt find out what was wrong
#pragma once
#include<iostream>
using namespace std;
struct Node {
public:
int coefficient;
int power;
Node* Next;
int getcoefficient()
{
return this->coefficient;
}
int getpower()
{
return this->power;
}
};
class Polynomial {
private:
Node* Head;
Node* Tail;
public:
Polynomial();
int getco();
int getpow();
Polynomial(int arraycoefficients[], int arraypower[], int n);
~Polynomial();
void insert(int coefficient1, int power1);
void remove(int power1);
double Evaluate(double value);
Polynomial operator+(Polynomial O2);
/*Polynomial& operator=(Polynomial& p);*/
int degree()const;
void merge(Polynomial p);
void removeAll();
friend istream& operator>>(istream& in, Polynomial& P);
friend ostream& operator<<(ostream& out, const Polynomial& P);
};
and this is the cpp for the header file
#include "Polynomial.h"
#include<math.h>
#include <iostream>
using namespace std;
Polynomial::Polynomial()
{
Head = Tail = NULL;
}
int Polynomial::getco()
{
return Head->coefficient;
}
int Polynomial::getpow()
{
return Head->power;
}
Polynomial::Polynomial(int arraycoefficients[], int arraypower[], int n)
{
Head = NULL;
Tail = NULL;
for (int i = 0; i < n; i++) {
insert(arraycoefficients[i], arraypower[i]);
}
}
Polynomial::~Polynomial()
{
removeAll();
}
void Polynomial::insert(int coefficient1, int power1)
{
Node* node = new Node;
node->coefficient = coefficient1;
node->power = power1;
node->Next = NULL;
if (Head == NULL) {
Head = Tail = node;
return;
}
//addition at head
if (power1 == Head->power) {
Head->coefficient = Head->coefficient + coefficient1;
return;
}
//insert at head
if (power1 < Head->power) {
node->Next = Head;
Head = node;
return;
}
Node* temporary = Head;
while (temporary->Next != NULL) {
if (temporary->power == power1) {
temporary->coefficient = temporary->coefficient + coefficient1;
return;
}
if (power1 > temporary->power && power1 < temporary->Next->power) {
node->Next = temporary->Next;
temporary->Next = node;
return;
}
temporary = temporary->Next;
}
//insert at last
if (temporary->power == power1) {
temporary->coefficient = temporary->coefficient + coefficient1;
return;
}
temporary->Next = node;
Tail = node;
}
void Polynomial::remove(int pw)
{
if (Head == NULL)
return;
//only one node
if (Head->power == pw && Head == Tail) {
delete Head;
Head = Tail = NULL;
return;
}
Node* temporary = Head;
while (temporary->Next != NULL) {
if (pw == temporary->Next->power)
{
Node* node = temporary->Next;
temporary->Next = temporary->Next->Next;
if (temporary->Next == NULL)
Tail = temporary;
delete node;
return;
}
temporary = temporary->Next;
}
}
double Polynomial::Evaluate(double value)
{
Node* temporary = Head;
double result = 0.0;
while (temporary != NULL) {
result =result+ (temporary->coefficient * pow(value, temporary->power));
temporary = temporary->Next;
}
return result;
}
/*Polynomial& Polynomial::operator=(Polynomial& p)
{
Node* temporary = p.Head;
int pp;
int cc;
removeAll();
while (temporary != nullptr) {
pp = temporary->getpower();
cc = temporary->getcoefficient();
insert(cc,pp);
temporary = temporary->Next;
}
return *this;
}*/
int Polynomial::degree() const
{
if (Head == NULL)
{
cout << "Empty polynomial\n";
return -1;
}
return Tail->power;
}
void Polynomial::merge(Polynomial p)
{
int count = 0;
Node* temporary = p.Head;
while (temporary != NULL) {
insert(temporary->coefficient, temporary->power);
temporary = temporary->Next;
}
p.removeAll();
return;
}
void Polynomial::removeAll()
{
if (Head == NULL)
return;
Node* CurrentNode = Head;
Node* NextNode = NULL;
while (CurrentNode != NULL)
{
NextNode = CurrentNode->Next;
delete CurrentNode;
CurrentNode = NextNode;
}
Head = Tail = NULL;
}
istream& operator>>(istream& in, Polynomial& P)
{
int num;
cout << "Please enter number of nodes\n";
cin >> num;
int c, p;
for (int i = 0; i < num; i++)
{
cout << "Please enter the pair of (coefficient,power)\n";
in >> c >> p;
P.insert(c, p);
}
return in;
}
ostream& operator<<(ostream& out, const Polynomial& P)
{
Node* temporary = P.Head;
if (temporary == NULL)
{
out << "Empty polynomial\n";
return out;
}
else {
out << "Polynomial is:\n";
while (temporary != NULL) {
if (temporary->power == 0)
out << temporary->coefficient << " + ";
else if (temporary->Next == NULL)
out << temporary->coefficient << "x^" << temporary->power;
else
out << temporary->coefficient << "x^" << temporary->power << " + ";
temporary = temporary->Next;
}
}
out << endl;
return out;
}
//Polynomial operator+(Polynomial& p1, Polynomial& p2)
Polynomial Polynomial::operator+(Polynomial O2)
{
Polynomial SumOfPolies;
Node* temporary = Head;
while (temporary != NULL) {
SumOfPolies.insert(temporary->coefficient, temporary->power);
temporary = temporary->Next;
}
temporary = O2.Head;
while (temporary != NULL) {
SumOfPolies.insert(temporary->coefficient, temporary->power);
temporary = temporary->Next;
}
return SumOfPolies;
}
and this is the main
#include <iostream>
#include "Polynomial.h"
using namespace std;
int main()
{
int X[] = { 2,4,1,3,5 };
int Z[] = { 1,2,0,3,4 };
Polynomial F1(X, Z, 5);
cout << F1 << endl;
cout << F1.degree() << endl;
Polynomial F2;
F2.insert(3, 2);
F2.insert(1, 6);
F2.insert(2, 7);
cout << F2 << endl;
Polynomial F3;
cout << "Here\n";
F3 = F1 + F2;
cout << "Here\n";
cout << F3;
return 0;
}

IMHO it's the time you should learn using debugger.
But if I had to guess I would say the most suspicious part I see in your code so far is this instruction:
return SumOfPolies;
in Polynomial Polynomial::operator+(Polynomial O2).
With this return you cause the program to make a copy of a local variable SumOfPolies. However, you did not provide a copy constructor to the Polynomial class, so compiler creates a default copy member-by-member. This means a copied object, which shall be returned, shares the same list of Nodes with SumOfPolies. But SumOfPolies will be destroyed immediately after, because this is just return from the method – and in the destructor if will delete all its Nodes thus invalidating the Head and Tail pointers in the returned copy.
There are other mistakes and imperfections, unrelated to what you experience now.
For example, you create a new Node object in the insert method even though if may be unnecessary if power1 == Head->power – but you do not delete it, and the abandoned Node object remains in memory for ever (or rather until your program terminates).
You mix NULL and nullptr.
You also declared some variables where they're not necessary. For example in removeAll() the NextNode is not necessary at the function's scope, it may well be defined within the loop. You can drop the CurrentNode as well:
void Polynomial::removeAll()
{
while (Head != NULL)
{
Node* NextNode = Head->Next;
delete Head;
Head = NextNode;
}
Tail = NULL;
}
You may also drop using the Tail member. As far as I can see you need to initialize or modify it in seven places of your program, but you use it just in two—and you can easily get rid of it in both of them!
One is in remove(int pw) where you compare Tail to Head to check if the list is a single node only. Note this can be accomplished just by testing if Head->Next == NULL.
The other one is in degree(), where you need to access the highest power node. But you could test the Head node instead if only you reverse the order in which powers are stored.
With this simple change you would simplify nine pieces of your code! I suppose this is worth inverting direction of one < and two > operators.

You need a copy constructor that looks like this:
Polynomial::Polynomial(Polynomial const& other)
{
Node* head = other.Head;
while (head != nullptr)
{
insert(head->coefficient, head->power);
head = head->Next;
}
}
When you provide a user-defined implementation of it, you should also implement the copy assignment operator, the move constructor and the move assignment operator. See the Rule of Five and the Rule of Zero: https://en.cppreference.com/w/cpp/language/rule_of_three.

Related

Trying to initialize a linked list using array

I need to define a class of linked list,List, in a way such that object of class can be defined in two ways,
List obj1 = L1();//head=0
List obj2 = L2(given_arr[], size of array) // I would be given an array, whose elements are elements of list
so, I need to form a construter for both,
for obj1, Its easy.
List(){head=0};
But I am not abe to do so for second type of object.
I tried to form a program for this.
#include <iostream>
using namespace std;
class List {
class node {
public:
int val;
node* next;
};
public:
node* head;
int arr[];
List() { head = 0; }
List(int arr[], int size);
void addnode(int value) {
node* newnode = new node();
newnode->val = value;
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 display() {
if (head == NULL) {
cout << "List is empty!" << endl;
} else {
node* temp = head;
while (temp != NULL) {
cout << temp->val << " ";
temp = temp->next;
}
cout << endl;
}
}
};
List::List(int arr[], int size) {
int i;
head->val = arr[0];
for (i = 0; i < size; i++) addnode(arr[i]);
}
int main() {
int barr[4] = {9, 89, 0, 43};
List* M = new List();
List* L = new List(barr[4], 4);
L->display();
return 0;
}
This program doesn't work. Please suggest a way to do so.
Make these changes to your main().
int main() {
int barr[] = {9, 89, 0, 43}; // No need to specify size if you're initializing
// List* M = new List(); // unused
// Your array is barr, barr[4] makes no sense. You also don't allocate the List,
// the list allocates
List L = List(barr, sizeof(barr) / sizeof(barr[0]);
L.display(); // -> to .
return 0;
}
This now compiles, but immediately segfaults. Simply running the program in the debugger shows a simple error. The line head->val = arr[0]; attempts to dereference a null pointer. Which takes us to the next thing. Use nullptr, not NULL or 0.
Your array constructor was over-complicated, you just need this:
List::List(int arr[], int size) {
for (int i = 0; i < size; i++) addnode(arr[i]);
}
Your addnode() function already handled an empty list. Fixing that, your code should run. I made a couple other small changes, mostly trimming cruft out. Here's your complete code:
#include <iostream>
using namespace std;
class List {
class node {
public:
int val;
node* next;
};
public:
node* head = nullptr;
List() = default;
List(int arr[], int size);
void addnode(int value) {
node* newnode = new node();
newnode->val = value;
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 display() {
if (head == NULL) {
cout << "List is empty!" << endl;
} else {
node* temp = head;
while (temp != NULL) {
cout << temp->val << " ";
temp = temp->next;
}
cout << endl;
}
}
};
List::List(int arr[], int size) {
for (int i = 0; i < size; i++) addnode(arr[i]);
}
int main() {
int barr[] = {9, 89, 0, 43};
List L = List(barr, sizeof(barr) / sizeof(barr[0]));
L.display();
return 0;
}

Implementation of Queue in C++

When I study the DataStructrue in my school, I implemented the Queue.
School's DataStructure class process is below.
student implemnted the DS
student submit in Domjudge
Domjudge score the code based by test cases.
My freind implemented the Queue like below.
#include <iostream>
#include <string>
using namespace std;
class Node {
public:
int data;
Node* next;
Node() {}
Node(int e) {
this->data = e;
this->next = NULL;
}
~Node(){}
};
class SLinkedList {
public:
Node* head;
Node* tail;
SLinkedList() {
head = NULL;
tail = NULL;
}
void addFront(int X) {
Node* v = new Node(X); // new Node
if (head == NULL) {
// list is empty
head = tail = v;
}else {
v->next = head;
head = v;
}
}
int removeFront() {
if (head == NULL) {
return -1;
}else{
Node* tmp = head;
int result = head->data;
head = head->next;
delete tmp;
return result;
}
}
int front() {
if (head == NULL) {
return -1;
}else {
return head->data;
}
}
int rear() {
if (head == NULL) {
return -1;
}else {
return tail->data;
}
}
int empty() {
if (head == NULL) {
return 1;
}else {
return 0;
}
}
void addBack(int X) {
Node* v = new Node(X);
if (head == NULL) {
head = tail = v;
}else {
tail->next = v;
tail = v;
}
}
~SLinkedList() {}
};
class LinkedQ {
public:
int n = 0;
int capacity;
Node* f;
Node* r;
SLinkedList Q;
LinkedQ(int size) {
capacity = size;
f = NULL;
r = NULL;
}
bool isEmpty() {
return n == 0;
}
int size() {
return n;
}
int front() {
return Q.front();
}
int rear() {
return Q.rear();
}
void enqueue(int data) {
if (n == capacity) {
cout << "Full\n";
}else {
Q.addBack(data);
n++;
}
}
};
int main() {
int s, n;
string cmd;
cin >> s >> n;
listQueue q(s);
for (int i = 0; i < n; i++) {
cin >> cmd;
if (cmd == "enqueue") {
int x;
cin >> x;
q.enqueue(x);
}else if (cmd == "size") {
cout << q.size() << "\n";
}else if (cmd == "isEmpty") {
cout << q.isEmpty() << "\n";
}else if (cmd == "front") {
q.front();
}else if (cmd == "rear") {
q.rear();
}
}
}
And I implmented like this (Node class and main are same, So I pass the code)
#include <iostream>
#include <string>
using namespace std;
class Node{...};
class listQueue {
public:
Node* head;
Node* tail;
int capacity;
int n = 0;
listQueue() {
head = NULL;
tail = NULL;
}
void enqueue(int X) {
Node* v = new Node(X); // new Node
if (n==capacity) {
cout << "Full\n";
return;
}
if (head == NULL) {
// Queue is empty
head = tail = v;
}else {
v->next = head;
head = v;
}
}
int front() {
if (head == NULL) {
return -1;
}else {
return head->data;
}
}
int rear() {
if (head == NULL) {
return -1;
}else {
return tail->data;
}
}
int empty() {
if (head == NULL) {
return 1;
}else {
return 0;
}
}
~listQueue() {}
};
test cases are just enqueue
but my friend is correct, and my code has occured memory over error.
So I check the usage of memory in Domjudge, My friend code and My code has very big gap in memory usage.
Why these two codes have memory usage gap big?
P.S I can't speak English well. If there is something you don't understand, please tell me.
First, rear is incorrect. It checks head and return tail. It happens to correct when you first set head=tail=v but it might get wrong later.
int rear() {
if (head == NULL) {
return -1;
}else {
return tail->data;
}
}
Check the if statement below:
v is leaked if queue is full in enqueue in your implementation.
Don't use NULL in C++. You may refer to NULL vs nullptr (Why was it replaced?).
void enqueue(int X) {
Node* v = new Node(X); // new Node
if (n==capacity) { // You're leaking v;
cout << "Full\n";
return;
}
if (head == NULL) {
// Queue is empty
head = tail = v;
}else {
v->next = head;
head = v;
}
}

Exception thrown: write access violation (this->tail was nullptr)

I have compiled my code and it seemed to work correctly. But out of no-where I get the error (this->tail was nullptr). I have tried changing the creation of the new node. But nothing seems to work. I cannot tell where tail is being set to nullptr and messing up the code.
How would I go about fixing this problem? Is there any way to set tail to non-nullptr without ruining every other function? I am not too familiar with exception throwing, so if you could explain the situation it would help a lot.
#ifndef MYDLL_H
#define MYDLL_H
#include <iostream>
#include <new>
using namespace std;
class MyDLL
{
struct Node
{
int i;
Node* next;
Node* prev;
};
Node* head;
Node* tail;
public:
MyDLL();
~MyDLL();
void append(int);
void remove(int);
bool find(int) const;
void clear();
void print() const;
void reverse() const;
};
MyDLL::MyDLL()
{
head = nullptr;
tail = nullptr;
}
MyDLL::~MyDLL()
{
clear();
}
void MyDLL::append(int i)
{
Node *n = new Node{ i, nullptr, nullptr };
if (head = nullptr)
{
head = n;
tail = n;
}
else
{
n->prev = tail;
tail->next = n; **<--- This is where the exception thrown error is showing up**
tail = n;
}
}
void MyDLL::remove(int i)
{
Node* p = head;
Node* q = tail;
while (p != nullptr && p->i != i)
{
q = p;
p = p->next;
}
if (p = nullptr)
{
return;
}
if (q = nullptr)
{
head = p->next;
}
else
{
q->next = p->next;
}
if (p->next = 0)
{
tail = q;
}
else
{
p->next->prev = q;
}
delete(p);
}
bool MyDLL::find(int i) const
{
Node* p = tail;
while (p != nullptr)
{
if (p->i = i)
{
return (true);
}
p = p->prev;
}
return (false);
}
void MyDLL::clear()
{
while (tail != nullptr)
{
Node* p = tail;
tail = p->prev;
delete (p);
}
head = nullptr;
}
void MyDLL::print() const
{
Node* p = head;
while (p)
{
cout << p->i << "\t";
p = p->next;
}
cout << "\n";
}
void MyDLL::reverse() const
{
Node* p = tail;
while (p)
{
cout << p->i << "\t";
p = p->prev;
}
cout << "\n";
}
#endif
int main()
{
MyDLL list;
list.append(5);
list.append(6);
list.append(7);
list.append(8);
list.print();
list.reverse();
cout << system("pause");
}
This code is exactly why you want to use nullptr = tail instead of tail = nullptr. In particular, every time you "check" for tail to be a null pointer, you are assigning nullptr to tail, and then assign operator returns a value which gets then implicitly casted to a boolean value, giving you no errors. But the error is actually there. Replace the "=" operator with "==" when performing a comparison, unless you actually have a reason for assigning and checking the return value.
Please fix = with == in your code.
void MyDLL::append(int i)
{
Node *n = new Node{ i, nullptr, nullptr };
if (head == nullptr)
It is always recommended to do like the reverse comparison (nullptr == head)

Threads on xcode while compiling the c++ code

so I was trying to build this project on deque using the doubly linked list. but when I build it. it says build but gives threads and doesn't give the output as required.
I have re-implemented the major problem(copy constructor) and all the functions again and again but then it still gives me new threads every time.
this is the header file.
#pragma once
#include <stdexcept>
using namespace std;
class Node
{
public:
int data;
Node* next;
Node* previous;
Node();
Node(const int &x);
};
class Deque
{
public:
Deque();
Deque(const Deque &d);
Deque &operator= (const Deque &d);
~Deque();
void insertFront(const int &x);
void insertBack(const int &x);
int removeFront();
int removeBack();
int peekFront();
int peekBack();
bool empty() const;
int size()const;
friend ostream& operator << (ostream &out, const Deque &d);
private:
Node* front;
Node* rear;
};
this will be the .cpp (implementation file.)
//
// Deque_cmpt225.cpp
// Deque_cmpt225
//
// Created by Aryan Arora on 2017-10-09.
// Copyright © 2017 Aryan Arora. All rights reserved.
//
#include "Deque_cmpt225.h"
#include <iostream>
#include <stdexcept>
using namespace std;
Node:: Node()
{
previous = nullptr;
next = nullptr;
data = 0;
}
Node:: Node(const int &x)
{
Node();
data = x;
}
Deque:: Deque() //Empty Deque.
{
front = nullptr;
rear = nullptr;
}
Deque:: ~Deque()
{
if (this->empty())
return;
else{
Node* temp;
while (this->front->next != nullptr){
temp = this->front;
this->front = this->front->next;
delete temp;
}
temp = this->front;
this->front = nullptr;
this->rear = nullptr;
delete temp;
}
}
Deque:: Deque (const Deque &d) //Copy Constructor
{
if (d.empty()) //Deque is empty.
{
return;
}
Node* temp = d.front;
int x;
if (temp->next == nullptr) //Deque of just one node
{
x = temp->data;
Node *n1 = new Node (x);
n1->next = nullptr;
n1->previous = nullptr;
this->front = n1;
this->rear = n1;
}
else //Deque has more than one node
{
while (temp!= nullptr)
{
this->insertBack(temp->data);
temp = temp -> next;
}
}
}
Deque& Deque:: operator=(const Deque &d) //============================check again
{
if (this == &d)
return *this;
else
{
this->~Deque(); //DELETING THE DEQUE
Node* temp = d.front; //COPYING EACH NODE
while (temp != NULL)
{
this->insertBack(temp->data); //INSERTING AT THE BACK
temp = temp->next; //POINTING TEMP TO NEXT NODE
}
}
return *this;
}
void Deque:: insertFront(const int &x)
{
Node* temp = new Node(x);
temp->next = nullptr;
temp->previous = nullptr;
if (empty())
{
this->front = temp;
this->rear = temp;
}
else
{
temp->next = this->front;
temp->previous = nullptr;
this->front->previous = temp;
this->front = temp;
}
}
void Deque:: insertBack(const int &x)
{
Node* temp = new Node(x);
temp->next = nullptr;
temp->previous = nullptr;
if (empty())
{
this->front = temp;
this->rear = temp;
}
else
{
temp->next = nullptr;
temp->previous = this->rear;
this->rear->next = temp;
this->rear = temp;
}
}
int Deque:: removeFront()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else{
Node* temp;
temp = this->front;
int x = temp->data;
if ( this->front->next != nullptr )
{
this->front = this->front->next;
this->front->previous = nullptr;
}
else
{
this->front = nullptr;
this->rear = nullptr;
}
delete temp;
return x;
}
}
int Deque:: removeBack()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else{
Node* temp = this->rear;
int x = temp->data;
if ( this->rear->previous != nullptr )
{
this->rear = this->rear->previous;
this->rear->next = nullptr;
}
else
{
this->rear = nullptr;
this->front = nullptr;
}
delete temp;
return x;
}
}
int Deque:: peekFront()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else
{
return this->front->data;
}
}
int Deque:: peekBack()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else
{
return this->rear->data;
}
}
bool Deque:: empty() const
{
if (this->front == nullptr && this->rear == nullptr)
return true;
else
return false;
}
int Deque:: size() const
{
Node* temp = this->front;
int count = 0;
while (temp != nullptr)
{
count++;
temp = temp->next;
}
return count;
}
ostream& operator << (ostream &out, const Deque &d)
{
Node* temp = d.front;
out << "NULL -> ";
while (temp != nullptr)
{
out << temp->data << " <-> ";
temp= temp->next;
}
out << "<- NULL" << endl;
return out;
}
thanks in advance.
Your code has many problems..
Your Node constructor doesn't delegate properly..
Node::Node()
{
previous = nullptr;
next = nullptr;
data = 0;
}
Node::Node(const int &x)
{
Node(); //Creates a temporary node that gets destroyed immediately..
data = x;
}
It's much simpler if you change it to:
Node::Node() : Node(0) //Delegating constructor.
{
}
Node::Node(const int &x) : previous(nullptr), next(nullptr), data(x)
{
}
This point isn't really a problem, but worth mentioning.. You keep setting the Node pointers to nullptr right after construction. This is not necessary because your constructor already does that..
Node* temp = new Node(x);
temp->next = nullptr; //Not needed anymore with the above fixes.
temp->previous = nullptr; //Not needed anymore with the above fixes.
You never initialize your variables in the copy constructor..
In your constructor, you have (I changed it, but it has the same meaning):
Deque::Deque() : front(nullptr), rear(nullptr)
{
}
But in your copy constructor, you have:
Deque::Deque(const Deque &d)
{
//Other code here.. You never initialized front and rear to nullptr..
}
You never set front and rear to nullptr so empty() returns false since they are a "random" uninitialized value.. Then in insertBack you go on to access this and boom.. Access Violation.
To fix it, you do:
Deque::Deque(const Deque &d) : front(nullptr), rear(nullptr)
{
//Other code here..
}
Next issue is that your copy assignment operator is calling the destructor!
Deque& Deque::operator=(const Deque &d)
{
if (this == &d)
return *this;
else
{
this->~Deque() //YOU CANNOT DO THIS.. Create a private member function for cleaning up.. Then call that function in your destructor and call that function here.. You cannot invoke the destructor like this.
}
//....
}

Reversing a stack implemented using a linked list

This is a very simple program that implements a stack using a linked list. Kindly help me figure out the logical bug that makes the program crash on run.
class LLStack {
public:
struct Node {
int data;
Node* next;
Node(int n) {
data = n;
next = 0;
}
Node(int n, Node* node) {
data = n;
next = node;
}
};
LLStack();
LLStack(const LLStack&);
LLStack& operator = (const LLStack&);
~LLStack();
void push(int);
int pop();
int top();
bool isEmpty();
void flush();
private:
Node* head;
};
LLStack::LLStack() {
head = 0;
}
LLStack::LLStack(const LLStack& s) {
head = new Node(NULL);
head->data = s.head->data;
head->next = new Node(*(s.head->next));
}
LLStack::~LLStack() {
this->flush();
}
LLStack& LLStack::operator = (const LLStack& s) {
this->head = new Node(NULL);
this->head->data = s.head->data;
this->head->next = new Node(*(s.head->next));
return *this;
}
void LLStack::push(int x) {
if (head == 0) head = new Node(x);
else {
Node* temp = new Node(x, head);
head = temp;
}
}
int LLStack::pop() {
if (head == 0) {
cout << "\n\nNo elements to pop\n\n";
return -1;
}
else {
Node* temp = head;
int n = temp->data;
head = temp->next;
delete temp;
return n;
}
}
int LLStack::top() {
if (head == 0) {
cout << "\n\nNo elements in the stack\n\n";
return -1;
}
else {
return head->data;
}
}
bool LLStack::isEmpty() {
return (head == 0);
}
void LLStack::flush() {
if (head == 0) {
cout << "\n\nNo elements in the Stack to flush\n\n";
return;
}
cout << "\n\nFlushing the Stack: ";
Node* temp = 0;
while (head != 0) {
temp = head;
cout << temp->data << " ";
head = head->next;
delete temp;
}
cout << endl << endl;
}
This is the trouble-maker fuction:
void reverseStack(LLStack& s1) {
LLStack s2;
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
s1 = s2;
}
int main() {
LLStack s;
s.push(1);
s.push(2);
s.push(3);
s.push(4);
s.push(5);
reverseStack(s);
cout << "\n\nFlushing s:\n";
s.flush();
system("pause");
return 0;
}
I have implemented my own copy constructor and the copy assignment operator. I don't understand why it crashes on run. On flushing it displays garbage values before crashing.
The problem is your copy assignment operator. Consider:
void reverseStack(LLStack& s1) {
LLStack s2;
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
s1 = s2;
}
Everything works fine until you return from the function, at which point the destructor for s2 is called. The destructor calls flush(), which deletes all stack elements of s2. In your copy assignment operator (and copy constructor, at that), you create two nodes: head and head->next; the rest of the nodes are shared between the two stacks, so after s2 has been deleted, s1.head->next->next points to a node that has been deleted, but you still try to access it.
The solution is to have the copy assignment operator (and the copy constructor) create a proper deep copy of the stack, not just the first two elements, like this (also takes care of self assignment):
LLStack& LLStack::operator=(const LLStack& s) {
if (this==&s) return *this; // self assignment
flush(); // avoid memory leak
head = new Node(*s.head);
Node* s_ptr = s.head;
Node* t_ptr = head;
while (s_ptr->next) {
t_ptr->next = new Node(*s_ptr->next);
s_ptr = s_ptr->next;
t_ptr = t_ptr->next;
}
return *this;
}
Remember that the copy constructor should do the same.