For some reason when i run my C++ program on VS it compile and run smoothly and when i'm trying to run it on Linux Mint terminal it does compile without any errors but i'm not getting any feedback/printing to the terminal...it's just stuck - so i can't even guess where the problem is. any suggestions?
I'm really a noob when it comes to Linux...
my program contains 2 cpp class file, 2 header files (each for one class) and a main.cpp file which i'm trying to run like this:
g++ *.cpp -o myprog
./myprog
it does create a myprog file - but when i run it nothing happens, like i said.
my code:
btree.h
#include <iostream>
#ifndef _BTREE_H_
#define _BTREE_H_
class LinkedList;
struct node
{
int key_value;
node *left;
node *right;
};
class btree
{
friend class LinkedList;
public:
// Default constructor
btree();
~btree();
// Copy Constructor by list
btree(LinkedList &list);
// Copy Constructor by tree
btree(btree & bt);
// assignment operator from linked list
btree & operator=(const LinkedList & ls);
// assignment operator from tree
btree& operator=(const btree &bt);
// insert new value to binary tree
void insert(int key);
// mirror the tree
void mirror();
LinkedList* Tree2linkListbyDepth();
int getTreeDepth();
// print tree (in order)
friend std::ostream& operator<<(std::ostream& os, btree& dt);
private:
node* root;
bool isMirrored;
void copyConstructor(node *bt);
void destroyTree(node * tmp);
void insert(node* tmp, int key);
void mirrorInsert(node* tmp, int key);
void mirror(node * node);
LinkedList TreeToList(node *tmp, LinkedList *listToReturn, int depth);
int getTreeDepth(node * tmp);
friend std::ostream& travel(std::ostream & os, node* root);
};
#endif // _BTREE_H_
btree.cpp
#include"btree.h"
#include"Linkedlist.h"
#include<iostream>
using namespace std;
//constructor
btree::btree()
{
root = NULL;
isMirrored = false;
}
//destructor
btree::~btree()
{
destroyTree(this->root);
}
void btree::destroyTree(node * tmp)
{
if (tmp == NULL)
return;
destroyTree(tmp->left);
destroyTree(tmp->right);
delete(tmp);
}
//copy constructor - list to binary tree.
btree::btree(LinkedList &list)
{
while (list.head!=NULL)
{
insert(list.head->data);
list.head = list.head->next;
}
}
//copy constructor - inorder.
btree::btree(btree & bt)
{
if (bt.root == NULL)
root = NULL;
else
copyConstructor(bt.root);
}
void btree::copyConstructor(node *bt)
{
node* tmp = bt;
if (!tmp)
return;
copyConstructor(tmp->left);
insert(tmp->key_value);
copyConstructor(tmp->right);
}
//copying list to binary tree using "=" operator.
btree & btree::operator=(const LinkedList & ls)
{
Node *tmp = ls.head;
while (tmp != NULL)
{
insert(tmp->data);
tmp = tmp->next;
}
return *this;
}
//copying binary trees using "=" operator
btree & btree::operator=(const btree & bt)
{
if (this->root == bt.root) //cheking if not itself
return *this;
//למחוק את העץ הקיים
copyConstructor(bt.root);
return *this;
}
//inserting node to the binary tree
void btree::insert(int key)
{
node *tmp = root;
if (root != NULL)
{
if (isMirrored) //checking if the tree has been mirrored
mirrorInsert(tmp, key);
else
insert(tmp, key);
}
//if the tree is empty - adding a new node
else
{
root = new node;
root->key_value = key;
root->left = NULL;
root->right = NULL;
}
}
//regular insertion - smaller numbers to the left and bigger numbers to the right of the root.
void btree::insert(node* tmp, int key)
{
if (tmp->key_value >= key)
{
if (tmp->left == NULL)
{
tmp->left = new node();
tmp->left->key_value = key;
tmp->left->left = NULL;
tmp->left->right = NULL;
return;
}
insert(tmp->left, key);
}
else if (tmp->key_value < key)
{
if (tmp->right == NULL)
{
tmp->right = new node();
tmp->right->key_value = key;
tmp->right->left = NULL;
tmp->right->right = NULL;
return;
}
insert(tmp->right, key);
}
}
//mirrored insertion - smaller numbers to the right and bigger numbers to the left of the root.
void btree::mirrorInsert(node* tmp, int key)
{
if (tmp->key_value <= key)
{
if (tmp->left == NULL)
{
tmp->left = new node();
tmp->left->key_value = key;
tmp->left->left = NULL;
tmp->left->right = NULL;
return;
}
mirrorInsert(tmp->left, key);
}
else if (tmp->key_value > key)
{
if (tmp->right == NULL)
{
tmp->right = new node();
tmp->right->key_value = key;
tmp->right->left = NULL;
tmp->right->right = NULL;
return;
}
mirrorInsert(tmp->right, key);
}
}
//mirroring the binary tree and keeping track of it.
void btree::mirror()
{
if (isMirrored)
isMirrored = false;
else
isMirrored = true;
mirror(root);
}
void btree::mirror(node * node)
{
if (node == NULL)
return;
else
{
struct node * tmp;
mirror(node->left);
mirror(node->right);
tmp = node->left;
node->left = node->right;
node->right = tmp;
}
}
//constructing a list of lists, each list contains all the nodes at a specific level(depth).
LinkedList* btree::Tree2linkListbyDepth()
{
if (this == NULL)
return NULL;
node *tmp = root;
LinkedList *list;
int depth = this->getTreeDepth();
list = new LinkedList[depth]; //list of lists
for (int i = 0; i < depth; i++)
{
TreeToList(tmp, &list[i],(depth-i)); //adding to list[i] all the node in (depth-i) level from the binary tree using "TreeToList"
}
return list;
}
//returning a list with all the node at a specific level (depth).
LinkedList btree::TreeToList(node *tmp, LinkedList *listToReturn, int depth)
{
if (tmp == NULL)
return *listToReturn;
else if (getTreeDepth(tmp) == depth)
listToReturn->add(tmp->key_value);
else
{
TreeToList(tmp->left, listToReturn, depth);
TreeToList(tmp->right, listToReturn, depth);
}
return *listToReturn;
}
//returning the binary tree's depth.
int btree::getTreeDepth()
{
if (this->root == NULL)
return 0;
node* tmp = root;
return getTreeDepth(tmp);
}
int btree::getTreeDepth(node * tmp)
{
if (tmp == NULL)
return 0;
int leftDepth = getTreeDepth(tmp->left);
int rightDepth = getTreeDepth(tmp->right);
if (leftDepth > rightDepth)
return leftDepth+1;
else
return rightDepth+1;
}
ostream & travel(ostream &os, node* root)
{
node* tmp = root;
if (!root)
return os;
travel(os, root->left);
os << root->key_value << ",";
travel(os, root->right);
return os;
}
//printing the binary tree inorder - using recursive function "travel".
ostream & operator<<(ostream & os, btree & dt)
{
os << "Tree: ";
travel(os, dt.root);
os << endl;
return os;
}
Linkedlist.h
#include <iostream>
#ifndef _LINKEDLIST_H_
#define _LINKEDLIST_H_
class btree;
class Node
{
public:
Node* next;
int data;
};
using namespace std;
class LinkedList
{
friend class btree;
public:
int length;
Node* head;
LinkedList(btree &bt);
LinkedList(LinkedList &bt);
LinkedList();
~LinkedList();
void add(int data);
LinkedList & operator=(const LinkedList & bt);
LinkedList& operator=(const btree &bt);
friend std::ostream& operator<<(std::ostream& os, LinkedList& l);
private:
void copyBtToList(struct node *bt);
LinkedList(const LinkedList &bt);
void addToTail(int data);
};
#endif // !_LINKEDLIST_H_
Linkedlist.cpp
#include"Linkedlist.h"
#include"btree.h"
#include<iostream>
using namespace std;
LinkedList::LinkedList() {
length = 0;
head = NULL;
}
//copy constructors.
LinkedList::LinkedList(LinkedList& other) {
length = 0;
if (this->head == other.head)
return;
Node* tmp = other.head;
while (tmp != NULL)
{
this->addToTail(tmp->data);
tmp = tmp->next;
}
length = other.length;
}
LinkedList::LinkedList(const LinkedList& other) {
this->length = other.length;
if (length == 0)
return;
Node* tmp = other.head;
while (tmp != NULL)
{
this->add(tmp->data);
tmp = tmp->next;
}
}
//destructor.
LinkedList::~LinkedList() {
Node* next = head;
Node* cur = NULL;
while (next != NULL) {
cur = next;
next = next->next;
delete cur;
}
}
//copying binary tree to a list.
LinkedList::LinkedList(btree &bt) {
if (bt.root == NULL)
this->head = NULL;
else
copyBtToList(bt.root);
}
void LinkedList::copyBtToList(node *bt)
{
node* tmp = bt;
if (!tmp)
return;
copyBtToList(tmp->left);
add(tmp->key_value);
copyBtToList(tmp->right);
}
//adding node to the head of the list.
void LinkedList::add(int data) {
Node* node = new Node();
node->data = data;
if (head == NULL) { //list is empty
head = node;
head->next = NULL;
length++;
return;
}
node->next = head;
head = node;
length++;
}
//adding node to the tail of the list.
void LinkedList::addToTail(int data) {
Node* node = new Node();
node->data = data;
node->next = NULL;
if (this->length == 0 || head == NULL) { //list is empty
head = node;
length++;
return;
}
Node* curr = head;
while (curr != NULL && curr->next!=NULL)
curr = curr->next;
curr->next = node;
length++;
}
//copying lists using "=" operator.
LinkedList & LinkedList::operator=(const LinkedList & bt)
{
LinkedList tmp(bt);
std::swap(tmp.head, this->head);
return *this;
}
//copying binary tree to list using "=" operator.
LinkedList & LinkedList::operator=(const btree & bt)
{
LinkedList tmp;
tmp.copyBtToList(bt.root);
head = tmp.head;
return *this;
}
//printing list in the form of "(x1,x2,...,xn)" using "<<" operator.
ostream & operator<<(ostream & os, LinkedList & l)
{
Node *tmp = l.head;
os << "List: (";
while (tmp != NULL)
{
os << tmp->data << ",";
tmp = tmp->next;
}
os << ")"<<endl;
return os;
}
main.cpp
#include"Linkedlist.h"
#include"btree.h"
#include<iostream>
using namespace std;
int main()
{
btree *tree = new btree();
tree->insert(10);
tree->insert(6);
tree->insert(14);
tree->insert(5);
tree->insert(8);
tree->insert(12);
tree->insert(16);
LinkedList* l = tree->Tree2linkListbyDepth();
int dp = tree->getTreeDepth();
for (int i = 0; i < dp; i++) {
cout << l[i];
}
cout << *tree;
tree->mirror();
cout << *tree;
btree *tree1 = new btree(l[dp - 1]);
cout << *tree1;
btree *tree2 = new btree(*tree1);;
tree2->insert(100);
cout << *tree1;
cout << *tree2;
LinkedList* l1 = new LinkedList(*tree1);
LinkedList* l2 = new LinkedList(*l1);
l2->add(99);
cout << *l1;
cout << *l2;
delete tree;
}
my output on VS:
List: (10,)
List: (14,6,)
List: (16,12,8,5,)
Tree: 5,6,8,10,12,14,16,
Tree: 16,14,12,10,8,6,5,
Tree: 5,8,12,16,
Tree: 5,8,12,16,
Tree: 5,8,12,16,100,
List: (16,12,8,5,)
List: (99,16,12,8,5,)
btw - i'll be happy if you could also check if my "includes" was done correctly cause i couldn't figure it out so easily...
Thanks :)
Update:
I ran your code through AppVerifier. And it didn't initially find anything until I tried different variations of Debug/Release x86/x64 builds. And one point I got it to crash in Windows. And then it stopped reproing the crash. Then I changed all your initial tree->insert statements to take a rand() value instead of a fixed value, I could get it to crash 100% of the time in Windows. I'm not sure if I event needed AppVerifier, but I left it on. That's when I noticed your LinkedList destructor was attempting to delete a pointer at 0xcccccccc, which is uninitialized memory in a debug build.
Bottom line, here is your bug:
Your LinkedList copy constructor is not initializing the head pointer to NULL
Also, you have two copy constructors. One that takes a non-const reference and is public. And another one (with slightly different behavior) that takes a const reference, but is private.
You just want a single copy constructor that is both public and takes a const reference.
Here's the fix. Let this be the public constructor:
LinkedList::LinkedList(const LinkedList& other) {
length = 0;
head = NULL; // YOU FORGOT THIS LINE
Node* tmp = other.head;
while (tmp != NULL)
{
this->addToTail(tmp->data);
tmp = tmp->next;
}
length = other.length;
}
And then remove the other instance of the LinkedList copy constructor.
Another thing that looks suspicious. Your btree constructor that takes a linked list is corrupting your list. It's also forgetting to initialize the object before attempting the first insert.
btree::btree(LinkedList &list)
{
while (list.head != NULL)
{
insert(list.head->data);
list.head = list.head->next;
}
}
This is completely wrong. When you construct the btree from the list (being passed via reference), the constructor will modify the passed in LinkedList instance. When this constructor returns, the list instance will be returned to the call with a null head pointer, but a non-zero length member when the function returns.. And your LinkedList destructor will not be able to recurse the tree to free the memory. So you have both a memory leak and an invalid object state.
Do this instead.
btree::btree(const LinkedList &list)
{
root = NULL;
isMirrored = false;
Node* tmp = list.head;
while (tmp != NULL)
{
insert(tmp->data);
tmp = tmp->next;
}
}
It's also better to use initializer lists with constructors:
btree::btree(const LinkedList &list) :
root(NULL),
isMirrored(false)
{
...
}
You are welcome :)
old stuff:
Your cout statements are missing an end-of-line marker (which flushes the output):
Instead of statements like this:
cout << *tree;
Do this:
cout << *tree << endl;
But that's not your issue. You have a crash in your program:
[ec2-user#ip-172-31-10-108 stackover]$ g++ main.cpp btree.cpp LinkedList.cpp
[ec2-user#ip-172-31-10-108 stackover]$ ./a.out
List: (10,)
List: (14,6,)
List: (16,12,8,5,)
Tree: 5,6,8,10,12,14,16,
Tree: 16,14,12,10,8,6,5,
Segmentation fault
Looks like we have a bug that results in a crash. Let's compile with a debug build and analyze:
[ec2-user#ip-172-31-10-108 stackover]$ g++ main.cpp btree.cpp LinkedList.cpp -g
[ec2-user#ip-172-31-10-108 stackover]$ gdb ./a.out
GNU gdb (GDB) Amazon Linux (7.6.1-64.33.amzn1)
...
Reading symbols from /home/ec2-user/stackover/a.out...done.
(gdb) run
Starting program: /home/ec2-user/stackover/./a.out
Missing separate debuginfo for /usr/lib64/libstdc++.so.6
Try: yum --enablerepo='*debug*' install /usr/lib/debug/.build-id/87/91ddd49348603cd50b74652c5b25354d8fd06e.debug
Missing separate debuginfo for /lib64/libgcc_s.so.1
Try: yum --enablerepo='*debug*' install /usr/lib/debug/.build-id/a0/3c9a80e995ed5f43077ab754a258fa0e34c3cd.debug
List: (10,)
List: (14,6,)
List: (16,12,8,5,)
Tree: 5,6,8,10,12,14,16,
Tree: 16,14,12,10,8,6,5,
Program received signal SIGSEGV, Segmentation fault.
0x00000000004011b5 in btree::mirrorInsert (this=0x614ea0, tmp=0x21, key=16) at btree.cpp:133
133 if (tmp->key_value <= key)
Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.173.amzn1.x86_64
(gdb)
Short answer: it looks like you got some additional debugging to do around line 133 of btree.cpp. The value of tmp has a value of 0x21 - which is likely not a legitimate pointer value.
Related
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.
I am trying to write a code making a single linked list. I want to put all my array elements into each node and link them. But when I run my code I keep getting the segmentation fault error. I do not get why I am getting this error.
Can anybody help?? Thanks!!
linked_list_main.cc
#include <iostream>
#include "linked_list.h"
int main() {
int array[5];
List<int> list(array, 5);
std::cout << list;
return 0;
}
template <class T>
class Node {
public:
T data;
Node<T>* next;
};
This is my linked_list.h file.
class List {
private:
Node<T> *head;
public:
List() : head(NULL) {};
~List() {
Node<T>* ptr;
for(ptr = head; ptr == NULL; ptr = head->next)
delete ptr;
}
List(T* arr, int n_nodes){
Node<T>* tmp = head;
for(int i = 0; i < n_nodes; i++ ) {
Node<T>* node = new Node<T>;
node->data = arr[i];
if(tmp != NULL) {
node->next = tmp;
tmp = node;
}
}
}
friend std::ostream& operator<<(std::ostream& out, List<T>& rhs) {
Node<T>* cur = rhs.head;
while(cur != NULL) {
if(cur->next == NULL)
out << cur->data << " ";
else
out << cur->data << ", ";
cur = cur->next;
}
}
};
You need to change this
List(T* arr, int n_nodes){
Node<T>* tmp = head;
...
}
to this
List(T* arr, int n_nodes){
Node<T>* tmp = NULL;
...
head = tmp;
}
Pointers are tricky, learn to use a debugger. Will be the best hour you've ever spent when learning how to program.
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.
}
//....
}
Head and tail are getting populated, and print out the values, but nodePtr stays empty for some reason. When I debug in VS2015, head and tail number is getting populated, while field this stays empty
Here's Linked_List
#ifndef _LINKED_LIST_
#define _LINKED_LIST_
#include <iostream>
class LinkedList
{
public:
struct Node
{
int number;
Node * next;
Node() : number(NULL), next(NULL) {};
Node(int number_, Node * next_ = NULL)
{
number = number_;
next = next_;
}
}*head, *tail, *nodePtr;
LinkedList();
~LinkedList();
void add(int num);
friend std::ostream& operator<<(std::ostream& out, LinkedList& list);
private:
int size;
};
#endif // _LINKED_LIST_
Implementation file
include "linkedlist.h"
#include <iostream>
using namespace std;
LinkedList::LinkedList() : head(NULL), tail(NULL), nodePtr(NULL)
{
nodePtr = new Node();
}
LinkedList::~LinkedList()
{
Node * curr, *temp;
curr = head;
temp = head;
while (curr != NULL)
{
curr = curr->next;
delete temp;
temp = curr;
}
}
void LinkedList::add(int num)
{
Node * newNode = new Node();
newNode->number = num;
cout << newNode->number;
if (head == NULL)
{
head = newNode;
tail = newNode;
size++;
}
else
{
tail->next = newNode;
newNode->next = NULL;
tail = newNode;
size++;
}
//cout << nodePtr->number; //empty, or some random
//just some tests
cout << head->number;
if (head->next != NULL)
{
cout << head->next->number;
}
cout << tail->number;
cout << endl;
}
std::ostream & operator<<(std::ostream & out, LinkedList & list)
{
out << list.nodePtr->number << endl;
return out;
}
Main.cpp
#include <iostream>
#include "linkedlist.h"
using namespace std;
int main()
{
int num;
LinkedList list;
list.add(1);
list.add(2);
list.add(3);
cout << list;
cout << "Press 1: ";
cin >> num;
return 0;
}
You're missing a fundamental concept here. nodePtr is not some magical node that knows about all your other nodes, or knows about linked lists, or can be used to print all their numbers.
When you do this:
out << list.nodePtr->number << endl;
All you are doing is outputting the value that you initialized when you allocated a new Node and stored a pointer in nodePtr:
nodePtr = new Node();
That called the default constructor for Node which set nodePtr->number to zero. (side-note, you initialized it to NULL, not 0 -- you should not mix integer types with pointer types, so change it to initialize the value to 0).
Its value stays 0 because you never modify it. And nodePtr always points at that single node because you never modified nodePtr.
What you're actually wanting to do is print out your list. Let me suggest the normal way to do this, by starting at head and following the node linkages:
std::ostream & operator<<(std::ostream & out, const LinkedList & list)
{
for( Node *node = list.head; node != nullptr; node = node->next )
{
out << node->number << std::endl;
}
return out;
}
And finally, I suggest you remove nodePtr from your class completely.
You only use nodePtr in the constructor, you never change it's values.
I am making a function that removes the head node of a linked list and makes it the head of another linked list. I prototyped a function called moveNode in the outerclass called LinkedList, and I defined the function later on in my code. However, my compiler gives me error messages saying "class LinkedList::Node is private" and "LinkedList::Node* LinkedList:head is private. I don't understand what I need to do to fix it.
#include <iostream>
#include <cstdlib>
using namespace std;
class LinkedList
{
public:
LinkedList() { head = NULL; } // default constructor
friend ostream& operator<<( ostream& os, const LinkedList &ll );
void insertHead( int item ); // insert at the head of the list
int count(int searchFor, const LinkedList &ll);
void moveNode(LinkedList &other, LinkedList ¤tList);
private:
class Node // inner class for a linked list node
{
public:
Node( int item, Node *n );
int data; // the data item in a node
Node *next; // a pointer to the next node in the list
};
Node *head; // the head of the list
};
LinkedList::Node::Node(int item, Node *n)
{
data = item;
next = n;
}
ostream& operator<<(ostream& os, const LinkedList &ll)
{
LinkedList::Node *current;
for(current = ll.head; current != NULL; current = current->next)
{
os << current->data << " ";
}
}
int LinkedList::count(int searchFor, const LinkedList &ll)
{
LinkedList::Node *current;
current = ll.head;
int howmanytimes = 0;
while(current != NULL){
if(current->data == searchFor)
{
howmanytimes++;
}
}
cout << searchFor << " appears in " << ll << " | " << howmanytimes << "time(s)" << endl;
}
void moveNode(LinkedList &other, LinkedList ¤tList)
{
LinkedList::Node *current = other.head;
if(current!=NULL)
{
current->next = currentList.head;
}
}
void LinkedList::insertHead(int item)
{
head = new Node(item, head);
}
You are not qualifying the class name in the moveNode() implementation:
// note the LinkedList::
void LinkedList::moveNode(LinkedList &other, LinkedList ¤tList)
{
LinkedList::Node *current = other.head;
if(current!=NULL)
{
current->next = currentList.head;
}
}
That being said, this implementation does not match your description:
a function that removes the head node of a linked list and makes it the head of another linked list
An implementation that actually does what that says would look something more like this:
void LinkedList::moveNode(LinkedList &other, LinkedList ¤tList)
{
LinkedList::Node *current = other.head;
if (current != NULL)
{
other.head = current->next;
current->next = currentList.head;
currentList.head = current;
}
}
That being said, this method should be renamed to something like moveHead() instead. And since it is not accessing anything via the this pointer, it could even be declared static. Otherwise, I would suggest re-implementing it to remove the currentList parameter at least, eg:
void LinkedList::moveHead(LinkedList &other)
{
LinkedList::Node *newhead = other.head;
if (newhead != NULL)
{
other.head = newhead->next;
newhead->next = this->head;
this->head = newhead;
}
}