Taschenrechner als Kellerautomat



  • Hallo zusammen,

    http://img5.fotos-hochladen.net/thumbnail/bildschirmfotow07zd95n63_thumb.jpg

    dies ist meine Aufgabenstellung die ich erfüllen muss,
    ich weiß nicht woran es liegt, aber irgendwie habe ich einen totalen Hänger und mein Gehirn ist irgendwie auf 0 zurückgesetzt.

    Ich kriege es organisatorisch zunächst nicht hin mir einzuplanen welche Methode ich schreiben muss, und welche nicht und dann wiederum welche Methode wo hinein gehört, da ich ja noch die Klasse Calculator schreiben muss.

    Der aktuelle Quelltext den ich habe:

    #include <iostream>
    #include "Calculator.h"
    #include <stack>
    using namespace std;
    
    Calculator::compute()
    {
    }
    
    Calculator::berechnen()
    {
    	String expr;
    	int num1,num2;
    	cout << " Geben Sie Ihre Rechenoperation ein : " << endl;
    	cin >> expr;
    	if(expression.size(expr)==0)
    	{cout << " ungültige Eingabelänge "}
    	else
    	{
    		for(int i=0;i<expression.size(expr);i++)
    		{
    			switch(expr)
    			{
    				case '+':
    				case '*':
    				case '/':
    				case '-':
    
    			}
    		}
    	}
    
    }
    
    int main()
    {
    }
    

    Habe irgendwie totale Aussetzer. Klar könnte ich jetzt aus diesem Link:

    http://www.leda-tutorial.org/de/inoffiziell/ch02s04s01.html

    die Lösungen einfach herauskopieren, allerdings möchte ich es vorallem VERSTEHEN & ERKLÄREN können was ich da gemacht habe.

    Das Problem ist nur dass ich das bis morgen Nachmittag fertig haben muss, und ich da schon seit 4 Tagen dransitze, sich aber nicht wirklich etwas ergeben hat und es wäre für mich ein echtes Problem wenn ich dies nicht rechtzeitig schaffe.

    Meine Idee war halt, die Zeichen einlesen zu lassen in einer Schleife die solange läuft wie die Länge der String Variable expr. In der er Zeichen für Zeichen durchgeht und dementsprechend handelt mit push, pop oder add oder sub etc.. Und daraufhin muss ich mir dann nach der Berechnung das Ergebnis in einer anderen Variablen ausgeben lassen, in der die Ergebnisse zwischengespeichert werden.



  • Hallo

    Als erstes, nur mal eine kleine Übersicht, wie dein Programm ausschauen sollte, zumindest nach deiner Aufgabenstellung (Aufteilung in H+CPP schaffst du ja bestimmt selbst):

    #include <iostream>
    #include <string>
    #include <stack>
    
    class Calculator {
      private:
        std::string expr_;
        std::stack<int> stack_;
    
      public:
        Calculator(const std::string& expr) : expr_(expr) {}
        int compute() {
          // TODO Hier deine Berechnung hin...
          // .. und den Wert zurückliefern lassen
        }
    }
    
    int main() {
      std::string expr;
      std::cout << "Bitte um Eingabe: ";
      std::cin >> expr;
    
      // TODO weitere Prüfungen auf leer und so noch einbauen
    
      Calculator calc(expr);
      std::cout << "Der Wert: " << calc.compute() << "\n";
    }
    

    Und für deine Berechnung selbst, gehst du von links nach rechts durch die Zeichenfolge, und Wertest die einzelne Zeichen wie in dem Diagramm aus.

    Bei einer Zahl => ab auf den Stack.
    Bei einer mathematische Operation => letzten 2 Zahl vom Stack nehmen, die Operation darauf ausführen, und die Zahl wieder auf dem Stack
    Und wenn du am Ende bist, dann darf nur noch eine Zahl am Stack liegen, und diese entnimmst du und lieferst als Ergebnis zurück. (Achja wenn mehr als 1 Element auf dem Stack liegt, dann handelt es sich um eine Fehleingabe

    Soweit alles verstanden?

    PS: Auf ein Zeichen im string, kann man auch via [] zugreifen, also sowas:

    char z = str[0];
    

    Und fürs nächste mal, würde ich an deiner Stelle erst mal die Aufgabenstellung genau durchlesen, und anhand zuerst die die Struktur erzeugen. Und danach mit der Codierung anfangen.

    MfG mdn



  • Ja das habe ich soweit alles verstanden dankeschön schonmal!!!

    Es hakt eigentlich nur noch an dem pop Befehl.

    Das ist das einzige wo der Compiler noch meckert.

    er schmeißt nämlich raus:

    In file included from rechner.cpp:4:0:
    Rechner.h: In member function ‘int Calculator::compute()’:
    Rechner.h:21:27: error: void value not ignored as it ought to be
         int num2 = stack_.pop();
                               ^
    Rechner.h:22:27: error: void value not ignored as it ought to be
         int num1 = stack_.pop();
    


  • Auch wenn ich mir jetzt selber antworte, ist logisch, weil es ein void ist gibt es nichts zurück und kann somit also auch keine Variable festlegen.

    Allerdings ist mir dann 1. nicht geläufig wofür es diese Funktion überhaupt gibt, wenn sie nichts zurückgibt
    und besonders 2. Wie ich sonst an den Wert komme der ganz oben im Stack steht und an den, der darunter steht.

    Mit top(); an den obersten, aber wie an den darunter?

    Sorry für die Mehrfachposts 😃
    Habe es dann einfach so gelöst. Allerdings kriege ich zunächst entweder 0 oder einen Speicherzugriffsfehler als Ergebnis heraus.

    Hier mal mein Code:
    Rechner.h

    #include <iostream>
    #include <string>
    #include <stack>
    using namespace std;
    
    class Calculator {
    	private:
    		string expr_;
    		stack<int> stack_;
    
    	public:
    		string expr;
    		Calculator(const std::string& expr) : expr_(expr) {}
    		int compute() 						// Berechnung
    		{
    
    			for(int i = 0;i<expr.size();i++)
    			{
    				char c = expr[i];
    				int num1 = stack_.top();
    				stack_.pop();
    				int num2 = stack_.top();
    				switch(c)
    					{
    						case '+': stack_.push(num2+num1);
    						case '-': stack_.push(num2-num1);
    						case '/': stack_.push(num2/num1);
    						case '*': stack_.push(num2*num1);
    						case '1': stack_.push(1);
    						case '2': stack_.push(2);
    						case '3': stack_.push(3);
    						case '4': stack_.push(4);
    						case '5': stack_.push(5);
    						case '6': stack_.push(6);
    						case '7': stack_.push(7);
    						case '8': stack_.push(8);
    						case '9': stack_.push(9);
    						case '0': stack_.push(0);
    					}
    			}
    			return stack_.top();
    
    		}
    };
    

    rechner.cpp

    #include <iostream>
    #include <string>
    #include <stack>
    #include "Rechner.h"
    using namespace std;
    
    stack<int> stack_;
    int num2,num1;
    string expr;
    
    int main()
    {
    	string expr;
    	cout << " Ihre Eingabe zur Berechnung : " << endl;
    	cin >> expr;
    
    	if(expr.size()==0)
    		cout << " Ungültige Eingabe " << endl;
    	else
    	{
    	Calculator calc(expr);
    	std::cout << " Ihr Ergebnis : " << calc.compute() << "\n";
    	}
    }
    


  • 2 Fehler, die ich spontan sehe:

    * Deinem switch-case fehlen die breaks.

    * Du entnimmst dem Stack immer [edit]1 Element[/edit], auch wenn gar kein Rechenoperator eingelesen wurde.



  • Ersteres habe ich eben bereits schon korrigiert, daran lag es nicht.

    Zweiteres verstehe ich nicht ganz. Ich lese doch eine Zeichenkette ein, mit der solange gerechnet wird, bis Ihre Länge 0 entspricht bzw die Größe des Stacks dann.



  • Befasse mich erst seit 2 Tagen mit Klassen, aber das :

    public: 
        Calculator(const std::string& expr) : expr_(expr) {}
    

    check ich nicht. Also Calculator(...) dürfte der Konstruktor sein, aber :expr_(expr) ?????



  • huh?? schrieb:

    Befasse mich erst seit 2 Tagen mit Klassen, aber das :

    public: 
        Calculator(const std::string& expr) : expr_(expr) {}
    

    check ich nicht. Also Calculator(...) dürfte der Konstruktor sein, aber :expr_(expr) ?????

    Das ist eine (Member) Initializer List. Wichtiges Zeux.
    Darf eigentlich nicht fehlen, wenn Du über Konstruktoren lernst.

    Das tut es:
    Das Member Calculator::expr_ wird mit dem Wert des Arguments expr initialisiert.

    Hier steht mehr:
    http://en.cppreference.com/w/cpp/language/initializer_list



  • huwul schrieb:

    Zweiteres verstehe ich nicht ganz. Ich lese doch eine Zeichenkette ein, mit der solange gerechnet wird, bis Ihre Länge 0 entspricht bzw die Größe des Stacks dann.

    (Hab meinen Beitrag oben nochmal minimal editiert)

    Geh mal das Beispiel aus der Aufgabenstellung anhand Deines Codes durch. Noch bevor die 8 auf den Stack pushed (Z. 37), rufst Du

    int num1 = stack_.top();
                    stack_.pop();
                    int num2 = stack_.top();
    

    (Zeile 20-22) auf. Auf einem leeren Stack. Das kann nicht funktionieren! Der Teil des Codes darf nur dann aufgerufen werden, wenn das aktuelle Zeichen eins von +-*/ ist.



  • Okay soweit so gut, habe es jetzt in den Cases initialisiert.
    Sieht dann so aus:

    #include <iostream>
    #include <string>
    #include <stack>
    using namespace std;
    
    class Calculator {
    	private:
    		string expr_;
    		stack<int> stack_;
    
    	public:
    		string expr;
    		Calculator(const std::string& expr) : expr_(expr) {}
    		int compute() 						// Berechnung
    		{
    
    			for(int i = 0;i<expr.size();i++)
    			{
    				char c = expr[i];
    
    				switch(c)
    					{
    						case '+':{ 	int num1 = stack_.top();
    								stack_.pop();
    								int num2= stack_.top();
    								stack_.pop();
    								stack_.push(num2+num1);
    								break;}
    						case '-': {	int num1 = stack_.top();
    								stack_.pop();
    								int num2= stack_.top();
    								stack_.pop();
    								stack_.push(num2-num1);
    								break;}
    						case '/':{	int num1 = stack_.top();
    								stack_.pop();
    								int num2= stack_.top();
    								stack_.pop();
    								stack_.push(num2/num1);
    								break;}
    						case '*':{	int num1 = stack_.top();
    								stack_.pop();
    								int num2= stack_.top();
    								stack_.pop();
    								stack_.push(num2*num1);
    								break;}
    						case '1': stack_.push(1);
    								break;
    						case '2': stack_.push(2);
    								break;
    						case '3': stack_.push(3);
    								break;
    						case '4': stack_.push(4);
    								break;
    						case '5': stack_.push(5);
    								break;
    						case '6': stack_.push(6);
    								break;
    						case '7': stack_.push(7);
    								break;
    						case '8': stack_.push(8);
    								break;
    						case '9': stack_.push(9);
    								break;
    						case '0': stack_.push(0);
    								break;
    					}
    
    				//cout << " aktueller Kellerspeicher : " << stack_.top() << endl;
    			}
    			return stack_.top();
    
    		}
    };
    

    Leider erhalte ich damit allerdings immernoch Speicherzugriffsfehler.



  • Hallo

    Denn Fehler, denn du jetzt noch rein gebaut hast, ist wirklich ein Leichtsinns Fehler. In meiner Vorlage, hab ich dir schon eine Variable "expr_" eingebaut, die durch den Konstruktor auch richtig initialisiert wird.

    Du benutzt in deiner Berechnung aber eine neue Variable vom Namen "expr" (Z12 definiert, Z19+21 Zugriff). Was erst mal nicht schlimm ist, da die Schleife einfach nicht bearbeitet wird. Am Ende greifst du aber auf den Stack zu, auf dem ja kein Wert eingetragen wurde.

    Also Z12 entfernen und Z19+21 anpassen dann geht es.

    MfG mdn



  • Achja stimmt, da hat sich wohl ein Fehler eingeschlichen.

    Nun denn es funktioniert einwandfrei jetzt.

    Dankeschön schonmal für die super Hilfe!! 👍 👍

    Eine letzte Frage:

    Wenn man verlangt, dass nach jedem Durchlauf der Kellerspeicher ausgegeben werden soll, ist gemeint, dass die Zahl die im Stack quasi als erstes drinsteht ausgegeben werden soll oder die gesamten Zahlen?


  • Mod

    huwul schrieb:

    Wenn man verlangt, dass nach jedem Durchlauf der Kellerspeicher ausgegeben werden soll, ist gemeint, dass die Zahl die im Stack quasi als erstes drinsteht ausgegeben werden soll oder die gesamten Zahlen?

    Vermutlich alles. Es soll ja wohl der Kontrolle dienen, ob alles richtig gemacht wurde.



  • Habe das jetzt mal über Nacht bedacht, da ich später in der Übung Sitze wo ich das alles abgeben muss, um den Kellerspeicher komplett auszugeben bräuchte ich einen zweiten stack oder nicht?
    Sonst müsste ich doch per top und pop alles rauslesen lassen?
    Sry bin am Handy deshalb grade kein Code verfügbar



  • Ja um es komplett auszulesen brauchst du eine 2te Struktur, in der du die Daten zwischenspeicherst.

    Leiter unterstützt der Stack-Container keine iteratoren.

    MfG mdn



  • Als Lösung habe jetzt leider keinen code zur Verfügung wegen Handy, aber man kann den Stack ja quasi spiegelverkehrt in einem String speichern und in einer Schleife wieder ausgeben lassen.


  • Mod

    huwul schrieb:

    Als Lösung habe jetzt leider keinen code zur Verfügung wegen Handy, aber man kann den Stack ja quasi spiegelverkehrt in einem String speichern und in einer Schleife wieder ausgeben lassen.

    Mit dem obersten Element anzufangen macht doch am meisten Sinn?
    also im Prinzip

    void print_stack(stack<int> s) // by value
    {
        while (!s.empty())
        {
             ... // Ausgabe von s.top()
             s.pop();
        }
    }
    


  • Nicht direkt, hatte genau so eine whilw Schleife eingebaut aber sie gibt erst nur alle Werte raus und dann immer nur die Rechenoperation und nicht wenn zB Von unten drin steht 3 1 2 und 2+1 wird ausgeführt gibt ehe nur 3 aus und nicht 3 und 3.

    Deshalb das Speichern im Strinf


Anmelden zum Antworten