Napisałem program do liczenia wyrażeń ONP (odwrotnej notacji polskiej). Okazało się, że muszę go trochę zmienić i ta zmiana nastręcza mi problemów.
Z klawiatury wpisuję wyrażenie które następnie układane jest na stos. Następnie żeby obliczyć wartość wyrażenia muszę je odczytać od dołu (wiem, że mógłbym ze stosu zrobić listę, ale nie o to mi chodzi), zatem odwracam stos i przetwarzam kolejne elementy. Problem w tym, że przy przetwarzaniu dostaję segmentation fault i nie mogę dociec dlaczego.
Oto klasy mojego programu:
#include <iostream>
using namespace std;
class Stos;
class Element
{
protected:
Element* next;
public:
Element() : next(0) {};
Element(const Element & e);
Element * nxt() { return next; }
virtual string pokaz()=0;
virtual void przetwarzaj(Stos & s)=0;
virtual double pokaz_l()=0;
virtual char pokaz_z()=0;
virtual int precShow()=0;
friend class Stos;
Element* wpisz();
friend void rev(Stos & s);
};
class Liczba : public Element
{
private:
double el;
public:
Liczba(double l=0) {el=l;}
virtual double pokaz_l() {return el;}
virtual char pokaz_z() {return el;}
virtual int precShow() { return 0; }
virtual void przetwarzaj(Stos & s);
virtual string pokaz();
operator const double*();
};
class Dzialanie : public Element
{
private:
char el;
int prec;
public:
Dzialanie(char z=0);
virtual char pokaz_z() {return el;}
virtual double pokaz_l() {return el;}
virtual int precShow() { return prec; }
virtual void przetwarzaj(Stos & s);
virtual string pokaz();
Dzialanie& operator=(const Dzialanie & d);
operator const char*();
};
class Stos
{
private:
Element* top;
int count;
public:
Stos() : top(0), count (0) {};
~Stos();
Stos(const Stos & s);
Stos& operator=(const Stos & s);
void put(Element* e);
void pop();
Element * showTop();
Stos & reverse();
int countShow() { return count; }
friend class Element;
friend class Liczba;
friend class Dzialanie;
friend double oblicz_onp_lepsze(Stos & s);
void pokaz_caly();
};
double oblicz_onp_lepsze(Stos & s)
{
Stos s1;
int cnt=s.countShow();
for(int u=0; u<cnt; u++)
{
s.top->przetwarzaj(s1);
s.pop();
}
return s1.top->pokaz_l();
}
countShow() - liczba elementów na stosie
przetwarzaj(Stos & s) to funkcja wirtualna klasy Element, jeśli jest to Liczba to po prostu kładzie się ją na stosie, a jeśli operator - bierzemy dwie kolejne liczby ze stosu, wykonujemy na nich działanie i kładziemy na stos wynik.
void Dzialanie::przetwarzaj(Stos & s)
{
double a, b;
//double a = static_cast<Liczba*>(s.top)->el;
if(s.countShow()>1)
{
a = s.top->pokaz_l();
s.pop();
b = s.top->pokaz_l();
s.pop();
}
else
{
cout << "Wprowadzono niepoprawne wyrazenie ONP. Wychodze...";
exit(1);
}
Element * tmp;
double e;
switch (el)
{
case '+':
tmp = new Liczba(a+b);
break;
case '-':
tmp = new Liczba(b-a);
break;
case '/':
tmp = new Liczba(b/a);
break;
case '*':
tmp = new Liczba(a*b);
break;
case '^':
e = b;
if(a>0)
{
for(int j=1; j<a; j++)
e*=b;
}
else if (a<0)
{
for(int j=a; j<=0; j++)
e*=1/b;
}
else
e = 1;
tmp = new Liczba(e);
break;
default:
break;
}
s.put(tmp);
}
Sprawdzałem czy dobrze odwraca stos wyświetlając go - wszystko w porządku. Wrzucę jeszcze funkcję odwracającą, kładącą element i zdejmującą go.
Stos& Stos::reverse()
{
if(!count)
return *this;
Element* pt=top;
Element** tmp=new Element*[count];
for(int j=0; j<count; j++)
{
tmp[j]=pt;
pt=pt->next;
}
tmp[0]->next=0;
for(int j=1; j<count; j++)
tmp[j]->next=tmp[j-1];
top=tmp[count-1];
delete [] tmp;
return *this;
}
void Stos::put(Element* e)
{
e->next = top;
top = e;
count++;
}
void Stos::pop()
{
Element* tmp=top;
top=top->next;
delete tmp;
count--;
}
Przy debugowaniu widzę, że pętla w pierwszym przejściu działa poprawnie (przetwarza stos i dobrze rozpoznaje wskaźnik na obiekt Liczba), lecz już w drugim przejściu wywala segfaulta na linijce s.top->przetwarzaj(s1); - tak jakby s.top nie było tym czego oczekuje.
Mam nadzieję że nie zapomniałem o żadnym ważnym fragmencie kodu. Bardzo proszę o wskazówkę - jeśli rozwiążę ten problem, program będzie gotowy (: