I am working on my RPN calculator project.
At this moment I would like to put all the numbers from an entered calculation on stack, but unfortunately the process finishes with exit code 11 and I am stuck. It extacly happens when I type for example 3, and then 3+3.
I debugged it and I can see that the problem is in the line:
if(header!= nullptr) {
in here:
cell* List::Last() {
if(header!= nullptr) {
cell *i;
for(i = header; i->next != nullptr; i = i->next);
return i;
}
else return nullptr;
}
Exception EXC_BAD_ACCESS. I suppose it has something to do with my header in the list, but I have no idea why. I have read about this exception but it still doesn't help me. As far as I can see, most people get it with arrays. I would be very grateful for any hints... My full code is here (it is not finished yet, so it might seem that there is a lot of useless methods):
#include <iostream>
using namespace std;
typedef int element;
struct cell
{
element element;
cell * next;
};
class List {
protected:
cell * header;
public:
List();
~List();
void Insert(element x, cell * p);
void Delete(cell * p);
element Retrieve(cell * p);
cell * Locate(element x);
cell * First();
cell * Next(cell * p);
cell * Previous(cell * p);
cell * Last();
void print();
bool empty() {
return header == nullptr;
}
};
List::List() {
header = nullptr;
}
List::~List() {
cell *tmp;
while(header != nullptr) {
tmp = header;
header = header->next;
delete tmp;
}
}
void List::Insert(element x, cell * p) {
cell *tmp;
if (p != nullptr) {
tmp = p->next;
p->next = new cell;
p->next->element = x;
p->next->next = tmp;
} else {
header = new cell;
header->element = x;
header->next = nullptr;
}
}
element List::Retrieve(cell * p) {
return p->element;
}
void List::Delete(cell *p) {
cell* tmp;
tmp=p->next;
p->next = p->next->next;
delete tmp;
}
void List::print() {
for (cell *i = header; i != nullptr; i = i->next) {
cout << i->element << endl;
}
}
cell* List::Locate(element x) {
cell* tmp;
tmp = header;
while(tmp->next != nullptr) {
if(tmp->next->element == x) return tmp;
tmp = tmp->next;
}
return tmp;
}
cell* List::First() {
return header;
}
cell* List::Last() {
if(header!= nullptr) {
cell *i;
for(i = header; i->next != nullptr; i = i->next);
return i;
}
else return nullptr;
}
cell* List::Next(cell *p) {
return p->next;
}
cell* List::Previous(cell *p) {
cell* tmp;
tmp = header;
while(tmp->next != p) tmp = tmp->next;
return tmp;
}
class Stack {
List * list;
public:
Stack();
element top();
element pop();
void push(element x);
bool empty();
void makenull();
};
Stack::Stack() {
list = new List();
}
element Stack::top() {
return this->list->Retrieve(this->list->Last());
}
element Stack::pop() {
int tmp = this->list->Retrieve(this->list->Last());
cell* c = this->list->Previous(list->Last());
this->list->Delete(c);
return tmp;
}
void Stack::push(element x) {
this->list->Insert(x, this->list->Last());
}
bool Stack::empty() {
return this->list->empty();
}
void Stack::makenull() {
delete list;
}
class RPN {
Stack *stack;
public:
RPN();
int type;
int result;
char calculation[];
int menu();
int calculate();
bool isNum(char c);
bool isOperand(char c);
void putOnStack();
void enterCalculation();
void convertToRPN();
void convertFromRPN();
};
RPN::RPN() {
stack = new Stack();
type = 0;
result = 0;
}
int RPN::menu() {
cout << endl << "Choose option:" << endl;
cout << "1. Convert to RPN" << endl;
cout << "2. Convert from RPN" << endl;
cout << "3. RPN calculator" << endl;
cout << "4. Regular calculator" << endl;
cout << "5. Finish" << endl;
cin >> type;
switch (type) {
case 1:
enterCalculation();
convertFromRPN();
break;
case 2:
enterCalculation();
convertToRPN();
break;
case 3:
enterCalculation();
convertFromRPN();
calculate();
break;
case 4:
enterCalculation();
calculate();
break;
case 5:
break;
default:
cout << "Nie ma takiej opcji!" << endl;
break;
}
return type;
}
bool RPN::isNum(char c) {
return isdigit(c);
}
bool RPN::isOperand(char c) {
return c == '+' || c == '-' || c == '/' || c == '*';
}
void RPN::putOnStack() {
for(int i = 0; i < strlen(calculation); i++)
if(isNum(calculation[i])) stack->push(calculation[i]);
}
void RPN::enterCalculation() {
cout << "Type your calculation:" << endl;
cin >> calculation;
putOnStack();
}
void RPN::convertToRPN() {
}
void RPN::convertFromRPN() {
}
int RPN::calculate() {
return result;
}
int main() {
auto *rpn = new RPN();
while(rpn->type != 5)
rpn->menu();
return 0;
}
try this:
cell* List::Last() {
cell *i = header;
while(i->next != nullptr && i != nullptr)i=i->next;
return i;
}
Thank you for all your help. I managed to cope with that problem.
Maybe this will help somebody, I post my code below.
#include <iostream>
using namespace std;
typedef string element;
struct cell {
string element;
cell * next;
};
class List {
public:
cell * header;
List();
~List();
element Retrieve(cell * p);
cell* Previous(cell * p);
cell * Last();
void Insert(const element &x, cell * p);
void Delete(cell * p);
bool empty() {
return header == nullptr;
}
};
List::List() {
header = nullptr;
}
List::~List() {
cell *tmp;
while(header != nullptr) {
tmp = header;
header = header->next;
delete tmp;
}
}
element List::Retrieve(cell * p) {
return p->element;
}
void List::Delete(cell *p) {
cell* tmp;
if(p->next == nullptr) {
cout << "Error! No next element to delete!" << endl;
} else if(p->next->next == nullptr) {
delete p->next;
p->next = nullptr;
} else {
tmp = p->next;
p->next = p->next->next;
delete tmp;
}
}
cell* List::Previous(cell *p) {
if(p == header) {
cout << "There is no previous element for the header!" << endl;
return nullptr;
} else {
if(header -> next == p) {
return header;
} else {
cell *tmp = header;
while(tmp->next != p) tmp = tmp->next;
return tmp;
}
}
}
void List::Insert(const element &x, cell * p) {
cell *tmp;
if (p != nullptr) {
if(p -> next == nullptr) {
p->next = new cell;
p->next->element = x;
p->next->next = nullptr;
} else {
tmp = p->next;
p->next = new cell;
p->next->element = x;
p->next->next = tmp;
}
} else {
header = new cell;
header->element = x;
header->next = nullptr;
}
}
cell* List::Last() {
if(header != nullptr) {
if(header-> next == nullptr) return header;
else {
cell *i;
for(i = header; i->next != nullptr; i = i->next);
return i;
}
}
else return nullptr;
}
class Stack {
public:
List * list;
Stack();
void push(const element &x);
void makenull();
bool empty();
element pop();
element top();
};
Stack::Stack() {
list = new List();
}
void Stack::makenull() {
this->list->header = nullptr;
}
bool Stack::empty() {
return this->list->empty();
}
element Stack::top() {
return this->list->Retrieve(this->list->Last());
}
element Stack::pop() {
string tmp;
if(list->Last() == list->header) {
tmp = this->list->header->element;
this->list->header = nullptr;
} else {
tmp = this->list->Retrieve(this->list->Last());
cell* c = this->list->Previous(list->Last());
this->list->Delete(c);
}
return tmp;
}
void Stack::push(const element &x) {
if(this->list->header != nullptr) {
this->list->Insert(x, this->list->Last());
} else {
this->list->header = new cell;
this->list->header->element = x;
this->list->header->next = nullptr;
}
}
class RPN {
public:
RPN();
~RPN();
Stack *stack;
int type;
string calculation;
int menu();
string convertToRPN();
string convertFromRPN();
double calculateRPN();
void enterCalculation();
bool isNum(string s);
bool isOperator(char c);
int compareOperators(string op1, string op2);
};
RPN::RPN() {
stack = new Stack();
type = 0;
}
RPN::~RPN() {
delete stack;
}
int RPN::menu() {
cout << endl << "Choose option:" << endl;
cout << "1. Convert from RPN" << endl;
cout << "2. Convert to RPN" << endl;
cout << "3. RPN calculator" << endl;
cout << "4. Calculator" << endl;
cout << "5. Exit" << endl;
cin >> type;
cin.ignore();
switch (type) {
case 1:
enterCalculation();
convertFromRPN();
break;
case 2:
enterCalculation();
convertToRPN();
break;
case 3:
enterCalculation();
calculateRPN();
break;
case 4:
enterCalculation();
calculation = convertToRPN();
calculateRPN();
break;
case 5:
break;
default:
cout << "No such option! Choose a correct one." << endl;
break;
}
return type;
}
bool RPN::isNum(string s) {
return !s.empty() && std::find_if(s.begin(), s.end(), [](char c) { return !isdigit(c); }) == s.end();
}
bool RPN::isOperator(char c) {
return (c == '+' || c == '-' || c == '*' || c == '/');
}
int RPN::compareOperators(string op1, string op2) {
if ((op1[0] == '*' || op1[0] == '/') && (op2[0] == '+' || op2[0] == '-')) return -1;
else if ((op1[0] == '+' || op1[0] == '-') && (op2[0] == '*' || op2[0] == '/')) return 1;
return 0;
}
void RPN::enterCalculation() {
calculation[0] = 0;
cout << "Input expression:" << endl;
getline(cin, calculation);
}
string RPN::convertToRPN() {
auto len = static_cast<int>(calculation.length());
stack->makenull();
string RPNcalc;
RPNcalc.clear();
int j = 0;
int par1 = 0;
int par2 = 0;
while(isspace(calculation[j])) j++;
if(!isNum(string(1, calculation[j])) && (calculation[j] != '(')) {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
j = 0;
while(isspace(calculation[len-1-j])) j++;
if(!isNum(string(1, calculation[len-1-j])) && (calculation[len-1-j] != ')')) {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
for (int i = 0; i < len; i++) {
if (isNum(string(1, calculation[i])) || calculation[i] == '.') {
if(isspace(calculation[i+1])) {
RPNcalc.push_back(calculation[i]);
RPNcalc.push_back(' ');
} else {
if(isNum(string(1, calculation[i])) && calculation[i+1] != '.' && !isNum(string(1, calculation[i]))) {
RPNcalc.push_back(calculation[i]);
RPNcalc.push_back(' ');
} else if(isOperator(calculation[i+1])) {
RPNcalc.push_back(calculation[i]);
RPNcalc.push_back(' ');
} else if(calculation[i+1] == ')') {
RPNcalc.push_back(calculation[i]);
RPNcalc.push_back(' ');
} else {
RPNcalc.push_back(calculation[i]);
}
}
} else if (isOperator(calculation[i])) {
while(!stack->empty() && stack->top()[0] != '(' && compareOperators(stack->top(), string(1, calculation[i])) <= 0) {
RPNcalc.push_back(stack->pop()[0]);
RPNcalc.push_back(' ');
}
stack->push(string(1, calculation[i]));
} else if(calculation[i] == '(') {
par1++;
stack->push(string(1, calculation[i]));
} else if(calculation[i] == ')') {
par2++;
while(!stack->empty()) {
if(stack->top()[0] == '(') {
stack->pop();
break;
}
RPNcalc.push_back(stack->pop()[0]);
RPNcalc.push_back(' ');
}
} else if(isspace(calculation[i])) {
} else {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
}
if(par1 != par2) {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
while(!stack->empty()) {
if(RPNcalc.back() != ' ') RPNcalc.push_back(' ');
RPNcalc.push_back(stack->top()[0]);
stack->pop();
}
if(type != 4) cout << "RPN expression: " << RPNcalc << endl;
return RPNcalc;
}
string RPN::convertFromRPN() {
auto len = static_cast<int>(calculation.length());
stack->makenull();
string num;
string right;
string left;
string newExpr;
int j = 0;
while(isspace(calculation[j])) j++;
if(!isNum(string(1, calculation[j]))) {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
j = 0;
while(isspace(calculation[len-1-j])) j++;
if(!isOperator(calculation[len-1-j])) {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
for (int i = 0; i < len; i++) {
if (isOperator(calculation[i])) {
right = stack->pop();
left = stack->pop();
newExpr.clear();
newExpr += '(';
newExpr += left;
newExpr += ' ';
newExpr += calculation[i];
newExpr += ' ';
newExpr += right;
newExpr += ')';
stack->push(newExpr);
} else if (isNum(string(1, calculation[i])) || calculation[i] == '.') {
if(isspace(calculation[i+1])) {
num.push_back(calculation[i]);
stack->push(num);
num.clear();
} else num.push_back(calculation[i]);
} else if(isspace(calculation[i])) {
} else {
cout << "Expression incorrect!" << endl;
string errStr = "err";
return errStr;
}
}
newExpr = stack->top();
newExpr.erase(newExpr.begin());
newExpr.erase(newExpr.end()-1);
cout << "Infix notation: " << newExpr;
return newExpr;
}
double RPN::calculateRPN() {
auto len = static_cast<int>(calculation.length());
stack->makenull();
double a = 0;
double b = 0;
double result = 0;
string num;
num.clear();
if(isNum(string(1, calculation[len-1]))) {
cout << "Expression incorrect!" << endl;
return 0;
}
for (int i = 0; i < len; i++) {
if (isNum(string(1, calculation[i])) || calculation[i] == '.') {
if(isspace(calculation[i+1])) {
num.push_back(calculation[i]);
stack->push(num);
num.clear();
} else num.push_back(calculation[i]);
} else if (isOperator(calculation[i])) {
a = stod(stack->pop());
b = stod(stack->pop());
switch (calculation[i]) {
case '*':
stack->push(to_string(a * b));
break;
case '/':
stack->push(to_string(b / a));
break;
case '-':
stack->push(to_string(b - a));
break;
case '+':
stack->push(to_string(a + b));
break;
default:
break;
}
} else if(isspace(calculation[i])) {
} else {
cout << "Expression incorrect!" << endl;
return 0;
}
}
result = stod(stack->pop());
if(!stack->empty()) {
cout << "Expression incorrect!" << endl;
return 0;
}
cout << "Result: " << result << endl;
return result;
}
int main() {
cout << endl << "POSTFIX-INFIX CALCULATOR AND CONVERTER "<< endl;
auto *rpn = new RPN();
while(rpn->type != 5)
rpn->menu();
return 0;
}
Related
What's wrong with this code?
I really don't know. I'm beginner. Sorry for my english.
#include <iostream>
using namespace std;
struct elem
{
int wartosc;
elem* nast;
elem* poprz;
};
class ListaDwukierunkowa
{
protected:
elem **lista;
public:
ListaDwukierunkowa(elem** lista)
{
this->lista = lista;
}
void dodaj_elem(int do_dodania)
{
if (*lista == nullptr)
{
*lista = new elem;
(*lista)->wartosc = do_dodania;
(*lista)->nast = nullptr;
(*lista)->poprz = nullptr;
}
else
{
elem *temp = *lista;
while (temp->nast != nullptr)
{
temp = temp->nast;
}
temp->nast = new elem;
temp->nast->wartosc = do_dodania;
temp->nast->nast = nullptr;
temp->nast->poprz = temp;
}
}
void wyswietl_elem()
{
cout << endl;
if (lista == nullptr)
{
cout << "Lista jest pusta" << endl;
}
while (lista != nullptr)
{
cout << "poprz: " << lista->poprz << " | ten: " << lista << " | war:" << lista->wartosc << " | nast:" << lista->nast << endl;
lista = lista->nast;
}
}
void usun_elem(int do_usun)
{
elem *temp = *lista;
if (*lista == nullptr)
return;
while (temp->wartosc != do_usun)
{
temp = temp->nast;
if (temp == nullptr)
return;
}
if (temp->poprz)
temp->poprz->nast = temp->nast;
else
*lista = temp->nast;
if (temp->nast)
temp->nast->poprz = temp->poprz;
delete temp;
}
int liczba_elem()
{
int liczba = 0;
while (lista != nullptr)
{
liczba += 1;
lista = lista->nast;
}
return liczba;
}
int liczba_elem_o_war(int x)
{
int liczba = 0;
while (lista != nullptr)
{
if (lista->wartosc == x)
{
liczba += 1;
}
lista = lista->nast;
}
return liczba;
}
bool czy_zawiera(int x)
{
bool czy = false;
while (lista != nullptr)
{
if (lista->wartosc == x)
{
czy = true;
}
lista = lista->nast;
}
return czy;
}
void zwolnij_liste()
{
while (*lista != nullptr)
{
elem* nast = (*lista)->nast;
delete *lista;
*lista = nast;
}
*lista = nullptr;
}
};
int main()
{
ListaDwukierunkowa lista;
lista.dodaj_elem(1);
lista.wyswietl_elem();
// dodaj_elem(&wsk, 12);
// dodaj_elem(&wsk, 9);
// dodaj_elem(&wsk, 8);
// dodaj_elem(&wsk, 9);
// dodaj_elem(&wsk, 9);
// wyswietl_elem(wsk);
// cout << liczba_elem(wsk) << endl;
// cout << liczba_elem_o_war(wsk, 9) << endl;
// cout << boolalpha << czy_zawiera(wsk, 12) << endl;
// usun_elem(&wsk, 1);
// wyswietl_elem(wsk);
// zwolnij_liste(&wsk);
}
error: request for member 'poprz' in '*((ListaDwukierunkowa*)this)->ListaDwukierunkowa::lista', which is of pointer type 'elem*' (maybe you meant to use '->' ?)
cout << "poprz: " << lista->poprz << " | ten: " << lista << " | war:" << lista->wartosc << " | nast:" << lista->nast << endl;
enter image description here
image of errors,
lista is of type elem**: a pointer to a pointer.
The -> operator defererences one level of pointers. So lista->poprz is the same as (*lista).poprz.
In this case you need to dereference twice: (*lista)->poprz.
Note: I have not tried to understand why lista is a pointer to a pointer. It could be that you simply want elem* instead.
Hello I am trying to create a Red-Black Tree in c++, The problem is on the left_rotate method. I print the tree in order using recursive method and included some extra std::cout to see what is going on. The problem is that when i insert values to the tree from 1-8, the root should be the number 4. Instead the root stucks at number 2 for some reason, when i try it the other way around from 10-1 the right_rotate method works like a charm. I have also added some cout to see where is the iterator going after fixing 1 violation. It goes to the right Path. when 8 number is inserted it recolors, then goes up to number 6 where it should perform a left_rotate but it doesnt for some reason.... here is the code
p.s : please forgive my english :)
struct Node
{
int value;
bool isBlack;
bool isLeft;
Node *parent, *left, *right;
};
class RBtree
{
private:
Node *root;
protected:
void inorder(Node *t)
{
if (t == nullptr)
return;
inorder(t->left);
if (t == root)
cout << "ROOT: \n";
cout << "value: " << t->value << " color: ";
if (t->isBlack)
cout << " B \n";
else
cout << " R \n";
if (!t->isLeft)
{
cout << "ITS A RIGHT CHILD \n";
}
else
{
cout << "ITS A LEFT CHILD \n";
}
if (t->parent)
cout << "PARENT: " << t->parent->value << "\n";
else
cout << "NONE\n";
if (t->left)
cout << "LEFT CHILD IS: " << t->left->value << "\n";
else
cout << "LEFT CHILD IS NULL \n";
if (t->right)
cout << "RIGHT CHILD IS: " << t->right->value << "\n\n";
else
{
cout << "RIGHT CHILD IS NULL \n\n";
}
cout << "--------------------- \n\n";
inorder(t->right);
}
void fix_violations(Node *);
void recolor(Node *t);
void left_rotate(Node *);
void right_rotate(Node *);
public:
RBtree()
{
root = nullptr;
}
void insert(int);
void remove(int);
void print_inorder()
{
inorder(root);
}
};
void RBtree::insert(int v)
{
Node * t = new Node(); // temp node
t->value = v;
t->isBlack = false;
t->isLeft = false;
t->parent = nullptr;
t->left = nullptr;
t->right = nullptr;
if (root == nullptr)
{
root = t;
root->isBlack = true;
return;
}
Node *it = root; // create iterator to root
while (it)
{
if (v < it->value)
{
if (!it->left)
{
it->left = t;
t->parent = it;
t->isLeft = true;
//cout << "inserted ";
break;
}
it = it->left;
}
else if (v > it->value)
{
if (!it->right)
{
it->right = t;
t->parent = it;
t->isLeft = false;
//cout << "inserted ";
break;
}
it = it->right;
}
else
{
break;
}
}
fix_violations(t);
}
// check violations method
void RBtree::fix_violations(Node *t)
{
cout << "Iterated on: ";
while (t != root)
{
cout << t->value << " ";
if (!t->parent || !t->parent->parent)
{
break;
}
if (!t->isBlack && !t->parent->isBlack)
{
bool u_isBlack = true;
if (!t->isLeft)
{
if (t->parent->parent->left)
u_isBlack = t->parent->parent->left->isBlack;
}
else
{
if (t->parent->parent->right)
u_isBlack = t->parent->parent->right->isBlack;
}
if (!t->isBlack && !u_isBlack)
{
cout << " recolor ";
recolor(t);
}
else if (!t->isBlack && u_isBlack)
{
if (t->isLeft && t->parent->isLeft)
{
cout << " right-rotation ";
right_rotate(t);
}
else if (!t->left && !t->parent->isLeft)
{
cout << " left-rotation ";
left_rotate(t);
}
else if (t->isLeft && !t->parent->isLeft)
{
//right_left_rotate(t);
}
else if (!t->isLeft && t->parent->isLeft)
{
// left_right_rotate(t);
}
else
;
}
}
t = t->parent;
}
cout << "\n\n";
root->isBlack = true;
}
void RBtree::recolor(Node *t)
{
Node *u; // uncle;
if (!t->isLeft)
u = t->parent->parent->left;
else
u = t->parent->parent->right;
t->parent->isBlack = true;
t->parent->parent->isBlack = false;
u->isBlack = true;
}
void RBtree::left_rotate(Node *t)
{
Node *p = t->parent;
Node *g = p->parent;
if (!g->parent) // if grand parent has no parent then it is root
{
// disconnect nodes
g->right = nullptr;
p->parent = nullptr;
// parents left child
Node *p_left = p->left;
if (p_left)
{ // if left child of parent exists disconnect it
p->left = nullptr;
p_left->parent = nullptr;
}
root = p;
root->left = g;
g->parent = p;
g->isLeft = true;
if (p_left)
{
g->right = p_left;
p_left->parent = g;
p_left->isLeft = false;
}
}
else
{
Node *pg = g->parent; // grand parent's parent
pg->right = nullptr;
g->right = nullptr;
g->parent = nullptr;
p->parent = nullptr;
Node *p_left = p->left;
if (p_left)
{
p->left = nullptr;
p_left->parent = nullptr;
}
pg->right = p;
p->parent = pg;
p->left = g;
g->parent = p;
g->isLeft = true;
if (p_left)
{
g->right = p_left;
p_left->parent = g;
p_left->isLeft = false;
}
}
// recolor
p->isBlack = true;
t->isBlack = false;
g->isBlack = false;
}
void RBtree::right_rotate(Node *t)
{
Node * p = t->parent; // parent
Node * g = p->parent; // grand-parent
Node * u = g->right; // uncle
if (!g->parent) // if grand-parent's parent is null then g is root
{
g->left = nullptr;
p->parent = nullptr;
Node *p_right = p->right;
if (p_right)
p_right->parent = nullptr;
root = p;
root->right = g;
g->parent = p;
g->isLeft = false;
if (p_right)
{
g->left = p_right;
p_right->parent = g;
p_right->isLeft = true;
}
}
else
{
Node *pg = g->parent;
pg->left = nullptr;
g->parent = nullptr;
g->left = nullptr;
Node *p_right = p->right;
if (p_right)
p_right->parent = nullptr;
pg->left = p;
p->parent = pg;
p->right = g;
g->parent = p;
g->isLeft = false;
if (p_right)
{
g->left = p_right;
p_right->parent = g;
p_right->isLeft = true;
}
}
// recolor
p->isBlack = true;
t->isBlack = false;
g->isBlack = false;
}
int main()
{
RBtree a;
a.insert(1);
a.insert(2);
a.insert(3);
a.insert(4);
a.insert(5);
a.insert(6);
a.insert(7);
a.insert(8);
a.print_inorder();
}
hi I'm tying to code my own list class actually it works like the std::vector class. The problem is when I use new to allocate memory for the next list,
it Works fine. but when i try to allocate memory for the target(data) it gets reclaimed when the program reaches to the end of the scope of push_back()
I dont understand why this two do not happen the same way and how can I use allocated memory for my data without it getting distroyed?
the code is here
#include <iostream>
#include <cstdlib>
using namespace std;
struct pos{
int x;
int y;
pos()
{
x = y = 0;
}
pos(int x, int y)
{
this->x = x;
this->y = y;
}
pos& operator=(pos rhs)
{
x = rhs.x;
y = rhs.y;
return *this;
}
bool operator==(const pos& rhs)
{
if(x == rhs.x && y == rhs.y)
return true;
else
return false;
}
~pos()
{
cout << "x =" << x << ", y =" << y << "got distorted!" << endl;
}
};
class list {
private:
pos *target;
list* next;
int index;
public :
list();
list(pos target);
void push_back (int first , int second);
void push_back (const pos target);
pos pop_back();
pos* search(int first , int second);
pos* search(pos target);
int erase(int index);
pos get(int index);
void change(const pos target,int index);
void change(int first,int second,int index);
~list();
};
void print(list lst);
// function declarations
list::~list()
{
cout << "list is destroyed!" << endl;
if(target != NULL)
delete target;
if(next != NULL)
delete next;
}
list::list()
{
target = NULL;
next = NULL;
index = 0;
}
list::list(pos target)
{
this->target = new pos(target);
index = 0;
next = NULL;
}
void list::push_back(const pos target)
{
cout << "push_back() begin" << endl;
list* it = this;
while(it->next != NULL)
{
it = it->next;
}
if(it->target == NULL)
{
it->target = new pos(target);
}
else
{
it->next = new list;
it->next->index = it->index+1;
//option one
it->next->target = new pos(target);
//option two
it->next->target = (pos*)malloc(sizeof(pos));
(*it->next->target) = target;
//it->next->next is already NULL
}
cout << "push_back() end" << endl;
}
void list::push_back(int first , int second)
{
push_back(pos(first,second));
}
pos list::pop_back()
{
print(*this);
list* it = this;
cout << "address of x is" << this << endl;
cout << "this->target is" << this->target << endl;
cout << (*target).x << endl;
if(it->target == NULL)
return *(new pos); // an error is occurred there is not any data to return! must find another solution maybe throw an exception
if(it->next == NULL)
{
pos return_data = *(it->target);
delete it->target;
it->target = NULL;
return return_data;
}
while(it->next->next != NULL)
{
cout << "it->target is" << it->target << endl;
it = it->next;
}
pos return_data = *(it->next->target);
delete it->next;
it->next = NULL;
return return_data;
}
pos* list::search(pos target)
{
list* it = this;
do
{
if(target == *(it->target))
return it->target;
if(it->next != NULL)
it = it->next;
else
return NULL;
}while(1);
}
pos* list::search(int first , int second){
return search(pos(first,second));
}
int list::erase(int index){
if(index < 0)
return 0;
list *it = this , *it_next = this->next;
if(index == 0)
{
if(it->next == NULL)
{
delete it->target;
return 1;
}
while(it_next->next != NULL)
{
it->target = it_next->target;
it = it_next;
it_next = it_next->next;
}//needs to be completed
}
do
{
if(it_next->index == index)
{
it->next = it_next->next;
delete it_next;
return 1;
}
if(it_next->next != NULL)
{
it = it_next;
it_next = it_next->next;
}
else
return 0;
}while(1);
return 1;
}
pos list::get(int index)
{
if(index < 0)
return *(new pos);//error
list* it = this;
do
{
if(it->index == index)
{
return *(it->target);
}
if(it->next != NULL)
it = it->next;
else
return *(new pos);//error , index is bigger than [list size] - 1
}while(1);
}
void list::change(const pos target,int index)
{
if(index < 0)
return ;//error
list* it = this;
do
{
if(it->index == index)
{
*(it->target) = target;
}
if(it->next != NULL)
it = it->next;
else
return;//error , index is bigger than [list size] - 1
}while(1);
}
void list::change(const int first,const int second,int index)
{
change(pos(first,second),index);
}
void print(list lst)
{
int idx = 0;
while(!(lst.get(idx)==pos(0,0)))
{
cout << "index " << idx << " : x = " << lst.get(idx).x << ", y = " << lst.get(idx).y << endl;
idx++;
}
}
int main(int argc, char const *argv[])
{
list x;
cout << "address of x is" << &x << endl;
x.push_back(1,1);
x.push_back(2,2);
x.push_back(3,3);
x.push_back(4,4);
x.push_back(5,5);
print(x);
cout << "--------------------------" << endl;
x.pop_back();
print(x);
cout << "--------------------------" << endl;
cout << x.get(2).x << endl;
x.erase(2);
print(x);
cout << "--------------------------" << endl;
return 0;
}
in other words why it->next->target and/or it->target get destroyed when push_back returns?
In
void list::push_back(const pos target)
target is being passed by value, so the target inside push_back is a temporary copy. When the function ends the copy will go out of scope and be destroyed. This is what you are seeing. Annoying, but not your real problem.
list violates the Rule of Three. This means when a list is copied it is not copied correctly. The pointers are copied and not the items pointed-at. Every time a list is copied, both the original and the copy point at the same places. When the copy goes out of scope and is destroyed, it takes the original's data with it.
It just so happens that you pass exclusively by value, so there is a lot of copying and destroying going on. The print function, for example, will incorrectly copy and then obliterate the provided listwhen it returns.
Solution: Add a copy constructor and an assignment operator to list that works its way through the list and copies all of the links and read up on pass by reference.
What is being destroy (or destructor being called) is the temporary that created as input parameter on the following line:
push_back(pos(first,second));
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to write own simple forward list implementation. I'd like to access element by cout << list[0]. I wrote the following code but instead of value I got something like x637c00539997. What did I do wrong?
What else can I improve in my code?
#include <iostream>
#include <assert.h>
#include <cstdio>
#include <cstring>
#include <memory>
using namespace std;
class myList{
public:
class myListExceptionEmpty: public exception
{
public:
virtual const char* what() const throw()
{
return "EMPTY";
}
};
void push_back(int valve);
int getSize();
bool isEmpty();
void removeFirst();
void remove(int x);
void dump();
void pop_front();
struct elem
{
std::shared_ptr<elem> next;
int val;
};
class proxy
{
public:
std::shared_ptr<myList::elem> position;
proxy(std::shared_ptr<myList::elem> pos)
{
position = pos;
}
};
std::shared_ptr<myList::proxy> operator[](int position);
private:
std::shared_ptr<elem> start;
std::shared_ptr<elem> getLastElement();
std::shared_ptr<proxy> current;
int size = 0;
};
ostream& operator<<(std::ostream& os, myList::proxy& obj)
{
os << obj.position->val;
return os;
}
shared_ptr<myList::proxy> myList::operator[](int position)
{
std::shared_ptr<elem> p = start;
for(int i=0;i<position;i++)
{
p = p->next;
if (p == NULL) throw std::out_of_range("out");
}
//cout << p->val;
std::shared_ptr<proxy> tmp(new myList::proxy(p));
current = tmp;
return current;
}
std::shared_ptr<myList::elem> myList::getLastElement()
{
std::shared_ptr<elem> p = start;
while(p->next != NULL ) p = p->next;
return p;
}
bool myList::isEmpty()
{
return size;
}
void myList::dump()
{
std::shared_ptr<elem> x = start;
while (x != NULL)
{
cout << x->val << endl;
x = x->next;
}
}
void myList::push_back(int valve)
{
std::shared_ptr<elem> p, n(new elem());
n->next = NULL;
n->val = valve;
p = start;
if(p != NULL)
{
while(p->next != NULL ) p = p->next;
p->next = n;
}
else start = n;
size++;
}
void myList::remove(int x)
{
if (size == 0) throw myListExceptionEmpty();
std::shared_ptr<elem> p, prv;
p = start;
while(p->next != NULL)
{
if (p->val == x)
{
prv->next = p->next;
size--;
}
prv = p;
p = p->next;
}
}
void myList::pop_front()
{
if (size == 0) throw myListExceptionEmpty();
std::shared_ptr<elem> p, prv;
p = start;
while(p->next != NULL)
{
prv = p;
p = p->next;
}
prv->next = NULL;
}
void myList::removeFirst()
{
if (size == 0) throw myListExceptionEmpty();
std::shared_ptr<elem> p;
p = start;
cout << start->val << endl;
if(p!= NULL)
{
start = p->next;
}
size--;
}
int myList::getSize()
{
return size;
}
int main()
{
myList array;
int size;
cin >> size;
char a;
int tmp;
for (int i=0; i<size; ++i) {
std::cin >> a;
if (a == 'D')
{
try{
array.removeFirst();
}
catch (myList::myListExceptionEmpty &e)
{
cout << e.what() << endl;
}
}
else if (a == 'A')
{
int tmp;
std::cin >> tmp;
array.push_back(tmp);
cout << "elem" << array[0];
}
else if (a == 'S') cout /*<< "Size:"*/ << array.getSize() << endl;
}
}
With regard to the question "what else to improve":
You're using shared pointers, great! Instead of using new use the corresponding routine make_shared (see C++ documentation).
Do not define classes in classes. Let each class have its own header and source file. It increases readability dramatically and even compiling gets faster by splitting all classes into different files (best way: use include guards). This way you can also leave the namespaces like myList::elem.
Use <cassert> instead of <assert.h>. You're using C++11 anyway, so why the need to use an old C-library?!
Just an example: Change void myList::remove(int x) to void myList::remove(const int& x). Let the compiler know that x is a read-only object. Do not call the int-copy constructor here (also at other code lines).
With regard to your 2nd question: your overloaded operator [] returns a shared-pointer and not the object this pointer is pointing at. Thus, it will print the address of the pointer.
This is program after fix. I used cout << *array[0]; instead of cout << array[0];. Than you for help
#include <iostream>
#include <memory>
using namespace std;
class MyListProxy;
class MyListExceptionEmpty: public exception
{
public:
virtual const char* what() const throw(){
return "EMPTY";
}
};
class MyList{
public:
void push_back(int valve);
int getSize() { return size; };
bool empty() { return size; };
void removeFirst();
void remove(const int& x);
void dump();
void pop_front();
void clear() {this->start = NULL; size = 0;}
struct elem
{
shared_ptr<elem> next;
int val;
};
shared_ptr<MyListProxy> operator[](int position);
private:
shared_ptr<elem> start;
shared_ptr<MyListProxy> current;
shared_ptr<elem> getEnd();
int size = 0;
};
class MyListProxy
{
public:
shared_ptr<MyList::elem> position;
MyListProxy(shared_ptr<MyList::elem> pos)
{
position = pos;
}
};
ostream& operator<<(ostream& os, MyListProxy& obj)
{
os << obj.position->val;
return os;
}
shared_ptr<MyListProxy> MyList::operator[](int position)
{
if (start == NULL) throw out_of_range("out");
shared_ptr<elem> p = start;
for(int i=0;i<position;i++){
p = p->next;
if (p == NULL) throw out_of_range("out");
}
return make_shared <MyListProxy>(p);
}
shared_ptr<MyList::elem> MyList::getEnd()
{
if (start == NULL) return start;
shared_ptr<elem> p = start;
while(p->next != NULL ) p = p->next;
return p->next;
}
void MyList::dump()
{
shared_ptr<elem> x = start;
while (x != NULL)
{
cout << x->val << endl;
x = x->next;
}
}
void MyList::push_back(int valve)
{
shared_ptr<elem> p;
auto last = this->getEnd();
auto a = make_shared<elem>();
last = a;
last->val = valve;
size++;
}
void MyList::remove(const int& x)
{
if (size == 0) throw MyListExceptionEmpty();
shared_ptr<elem> p, prv;
p = start;
while(p->next != NULL)
{
if (p->val == x)
{
prv->next = p->next;
size--;
}
prv = p;
p = p->next;
}
}
void MyList::pop_front()
{
if (size == 0) throw MyListExceptionEmpty();
start = start->next;
}
int main()
{
MyList array;
int size;
cin >> size;
char a;
int tmp;
for (int i=0; i<size; ++i) {
cin >> a;
if (a == 'D')
{
try{
cout << *array[0];
array.pop_front();
}
catch (MyListExceptionEmpty &e)
{
cout << "EMPTY" << endl;
}
catch (out_of_range &e)
{
cout << "EMPTY" << endl;
}
}
else if (a == 'A')
{
int tmp;
cin >> tmp;
array.push_back(tmp);
}
else if (a == 'S') cout /*<< "Size:"*/ << array.getSize() << endl;
cout << "SIZE::" << array.getSize() << endl;
}
}
I need to create a RPN (postfix notation) calculator which makes simple operations (+, -, *, /), while using a linked list to maintain the stack. I have got the majority of it done but am running into a few problems. I can calculate any two numbers with one operand (ex: 5 5 + = 10), but cannot do anything more than that. I have done some research online, and watched a few YouTube videos to get where I am at now, but most use the stack reference to do it. I have tried to combine tutorials on that, along with how to make my own stack.
I am quite new to this and am pretty lost on how to calculate a larger expression (ex: 5 5 5 + + = 15), and I also need to check for errors, which I have completed some, but the ones I'm struggling with are "too many operators," and "too many operands." With too many operators I'm assuming it has something to do with not being able to pop off a value because there isn't one there, but that's as far as I can get (if it's right, still not quite sure how to implement it). Any help with any of these 3 things, or anything else you can see here would greatly be appreciated.
#include<iostream>
#include<string>
#include<sstream>
#include<iomanip>
using namespace std;
class SLLNode
{
double data;
SLLNode *top;
SLLNode *ptr;
public:
SLLNode()
{
top = NULL;
ptr = NULL;
}
void pushVal(double val)
{
SLLNode *next = new SLLNode;
next -> data = val;
next -> ptr = top;
top = next;
}
double popVal()
{
SLLNode *next = new SLLNode;
next = top;
top = top -> ptr;
next -> ptr = NULL;
return next -> data;
delete next;
}
void print()
{
SLLNode *next = new SLLNode;
next = top;
cout << "= " << next -> data << endl << ">>";
next = next -> ptr;
delete next;
}
};
bool isOperator(const string& input)
{
string ops[] = {"+", "-", "*", "/"};
for(int i = 0; i < 4; i++)
{
if(input == ops[i])
{
return true;
}
}
return false;
}
void performOp(const string& input, SLLNode& stack)
{
double fVal, sVal;
int result = 0;
sVal = stack.popVal();
fVal = stack.popVal();
if(input == "+")
{
stack.pushVal(fVal + sVal);
}
else if(input == "-")
{
stack.pushVal(fVal - sVal);
}
else if(input == "*")
{
stack.pushVal(fVal*+ sVal);
}
else if(input == "/" && sVal != 0)
{
stack.pushVal(fVal / sVal);
}
if(input == "/" && sVal == 0)
{
cout << "Error: Division by zero" << endl;
result = 1;
}
if(result == 0)
{
stack.print();
}
}
int main()
{
string input;
SLLNode stack;
cout << "::::::::::::::::RPN CALCULATOR:::::::::::::::::" << endl;
cout << "::TYPE IN A POSTFIX EXPRESSION OR 'q' TO QUIT::" << endl;
cout << ":::::::::::::::::::::::::::::::::::::::::::::::" << endl << endl;
cout << ">>";
while(true)
{
cin >> input;
double num;
if(istringstream(input) >> num)
{
stack.pushVal(num);
}
else if (isOperator(input))
{
performOp(input, stack);
}
else if (input == "q")
{
return 0;
}
else
{
cout << "Error: Invalid input" << endl;
}
}
}
First I would recommend you use std::map<double> instead of rolling your own linked list, unless it is for learning purposes.
The main problem is in SLLNode::popVal() and SLLNode::print() where things got a little bit confused.
Here is what you need to change to fix it:
double popVal()
{
SLLNode *next = top -> ptr;
double ret = top -> data;
delete top;
top = next;
return ret;
}
void print()
{
cout << "= " << top -> data << endl << ">>";
}
There are many other things you could improve in your code but that should answer your question.
You have two operators, '*' and '+' in your expression to calculate multiplication. I have added & rearranged a bit of error checking,
int
performOp(const string& input, SLLNode& stack)
{
double fVal, sVal;
int result = 0;
if( stack.size < 2 )
{
cout << "Error: too few operands" << end;
stack.print();
return 1;
}
sVal = stack.popVal();
fVal = stack.popVal();
if(input == "+")
{
stack.pushVal(fVal + sVal);
}
else if(input == "-")
{
stack.pushVal(fVal - sVal);
}
else if(input == "*")
{
stack.pushVal(fVal * sVal); //problem was here
}
else if(input == "/" )
{
if(sVal == 0)
{
cout << "Error: Division by zero" << endl;
stack.print();
return 1;
}
stack.pushVal(fVal / sVal);
}
return 0;
}
Define a list node that contains head/tail, and counts the elements in your stack,
#include<iostream>
#include<string>
#include<sstream>
#include<iomanip>
using namespace std;
class SLLNode //single link list
{
public:
SLLNode *next;
double data;
SLLNode()
{
next = NULL;
data = 0;
}
void print()
{
SLLNode *node = NULL;
cout << "= " << data << endl << ">>";
}
};
Your stack implementation leaks memory, allocates unnecessary nodes, and is missing a couple of useful stack operations that will help you solve some of your problems. You need a destructor that empties your list in case you forget to empty it, and it would help to have a print the entire list. Anyway,
class SLList //single link list
{
SLLNode *head;
SLLNode *tail;
int _count;
public:
SLList()
{
head = NULL;
tail = NULL;
_count = 0;
}
~SLList()
{
while( !empty() ) { pop(); }
}
int size() { return _count; }
bool empty() { return (!head); return false; }
void push(double val)
{
SLLNode *node = new SLLNode;
node->data = val;
node->next = head;
++_count;
if(!tail) tail = node;
head = node;
}
double pop()
{
SLLNode *node = NULL;
if(!head) return 0;
node = head;
double val = node->data;
head = node->next;
--_count;
if(!head) tail = NULL;
delete node;
return val;
}
double tip()
{
SLLNode *node = NULL;
if(!head) return 0;
node = head;
double val = node->data;
return val;
}
void print()
{
SLLNode *node = NULL;
if(!head) return;
for( node=head; node; node=node->next )
node->print();
}
};
You might want to add more operators, extract that,
bool isOperator(const string& input);
int performOp(const string& input, SLList& stack);
static string BINOPS[] = {"+", "-", "*", "/"};
bool
isOperator(const string& input)
{
for(int i = 0; i < 4; i++) //should get size of BINOPS
{
if(input == BINOPS[i])
{
return true;
}
}
return false;
}
Check your stacksize prior to extracting items from your stack,
int
performOp(const string& input, SLList& stack)
{
double fVal, sVal;
int result = 0;
if( stack.size() < 2 )
{
cout<<"Error: too few operands"<<endl;
stack.print();
return 1;
}
sVal = stack.pop();
fVal = stack.pop();
if(input == "+")
{
stack.push(fVal + sVal);
}
else if(input == "-")
{
stack.push(fVal - sVal);
}
else if(input == "*")
{
stack.push(fVal * sVal);
}
else if(input == "/" )
{
if(sVal == 0)
{
cout << "Error: Division by zero" << endl;
stack.print();
return 1;
}
stack.push(fVal / sVal);
}
return 0;
}
You need some way to print your list. The forth language used ".", so here I have added a case to print the list using ".",
int
main()
{
string input;
SLList stack;
cout<<"::::::::::::::::RPN CALCULATOR:::::::::::::::::"<<endl;
cout<<"::TYPE IN A POSTFIX EXPRESSION OR 'q' TO QUIT::"<<endl;
cout<<":::::::::::::::::::::::::::::::::::::::::::::::"<<endl<<endl;
double num;
while(true)
{
cout << ">>";
cin >> input;
if(istringstream(input) >> num)
{
stack.push(num);
}
else if (isOperator(input))
{
performOp(input, stack);
}
else if (input == ".")
{
stack.print();
double val = stack.tip();
cout << "= " << val << endl << ">>";
}
else if (input == "q")
{
return 0;
}
else
{
cout << "Error: Invalid input" << endl;
}
}
}
I also cleaned up a couple of other errors.