Problem beim Taschenrechner mit rekursiven Abstieg
-
Hallo,
Ich benutzt das Buch C++ Einführung und professionelle Programmierung von Ulrich Breymann. Jedesfalls geht es im Kapittel 4.2.8 um das Programmiren eines Taschenrechner mithilfe der rekursiven Abstieg. Jedenfalls wird Hierfür ein Ableitungsbaum beutztt der so aussieht.// Punkte sind zu ignorrieren.
............................Ausdruck
..............................|
.........------------Summand ----------
...............|.............|...............|
............Faktor..........*...............Faktor
....... -------|------.........................|
.......|.......|.......|............................Zahl
.......(.......|.......)...............................|
...............|..................................... Ziffer
---------Ausdruck-------.....................|
|................|...............|....................4
..Summand...+............Summand
.....|..............................|
....Faktor....................Faktor
......|..........................|
.....Zahl.......................Zahl
.......|..........................|
......Ziffer.....................Ziffer
.......|...|........................|
.......1....2.......................3Hierbei wird (12+3)*4 ausgerechnet.
im Buch steht nun diese Programmcode;
using namespace std;
int main (void){
char ch;
while(true){cout << " \n>>";
cin.get(ch);
if(ch != 'e')
cout << ausdruck (ch);else break;
}
}
long ausdruck(char& c) { // übergabe per Referenz
long a; // hilfsvariable
if (c == '-'){ // - im Eingabestom überspringen
cin.get(c);
a = -summand(c); // rest an summand() übergeben}
if (c == '+'){
cin.get(c); // + überspringen
a = summand(c);}
while (c== '+'|| c == '-'){ //aufgepasstif(c == '+'){
cin.get(c) // + überspringen
a += summand (c);}
else {
cin.get(c); // - überspringen
a -= summand(c);
}return a;
}
}
long summand (char & c){
long s = faktor(c);
while (c == '*' || c == '/'){if (c=='*') {
cin.get(c); // * übersprinegn
s *= faktor(c);
}else {
cin.get(c); // / übersprinegn
s /= faktor(c);
}}
return s;
}
long faktor(char & c){
long f;if (c == '('){
cin.get(c); // ( übersprinegn
f = ausdruck (c);if( c != ')'){
cout << "Rechte Klammer fehlt!\n";
else cin.get(c) ; // ) übersprinegn}
else f = zahl (c);
return f;}
long zahl (char & c) {
long z = 0;
while(isdigit(c)){ // d.h. c >= '0' && c <= '9'/*isdigit() ist eine Fuktion was zu true ausgewertet wird falls c ein ziffernzeichen ist. Muss #inlcude <cctype> verwenden.*/
z = 10*z + long (c- '0');
cin.get(c);
}return z;
}
Nun heißt es, dass es den Leser über lassen wird das Programm zum laufen zu bringen, zu vervollständigen, einschließlich trennung von Prototypen und Definitionen.
Mir gelingt dies aber nicht. Könnt ihr mir hierbei bitte helfen und mir nochmal das ganze Prinzip genauer erklären. Danke
-
Ja, das können wir, aber nenne bitte erst die genauen Hürden, also klare Fragen zu konkreten Punkten, und bitte den Code mit C++ Tags einrahmen, sonst liest das keiner bzw. der Moderator hat Arbeit. Also wo klemmt es ganz genau?
Schaue Dir Deklaration/Definition an und die Trennung in Header- (xyz.h) und Implemetierungsdateien (xyz.cpp).
Dieses Tutorial ist vielleicht begleitend zur Begriffsklärung hilfreich: http://www.cpp-tutor.de/cpp/le01/main.html
-
Wie man seinen Beitrag lesbar formatiert
Codetags sind auch gut für ASCII-Zeichnungen. Die Krüppelei mit den Punkten wird bei jedem Leser anders aussehen, außer der Gemeinsamkeit, dass sie überall unlesbar ist.
-
Das Problem gibts auch in der neueren auflage des buchs. Lade dir doch die loesungen runter (Verzeichnis k3/7), die enthält auch nicht die Abtippfehler.
-
Ich habe meinen Text nochmal überarbeitet. Hoffe das er nun leserlicher ist. ps ist mein erster Beitrag in einem Forum.
Hallo,
Ich benutzt das Buch C++ Einführung und professionelle Programmierung von Ulrich Breymann. Jedesfalls geht es im Kapittel 4.2.8 um das Programmiren eines Taschenrechner mithilfe der rekursiven Abstieg. Jedenfalls wird Hierfür ein Ableitungsbaum beutztt der so aussieht.// Punkte sind zu ignorrieren. Ausdruck | ------------Summand ---------- | | | Faktor * Faktor -------|------ | | | | Zahl "(" | ")" | | Ziffer ---------Ausdruck------- | | | | 4 Summand + Summand | | Faktor Faktor | | Zahl Zahl | | Ziffer Ziffer | | | 1 2 3
Hierbei wird (12+3)*4 ausgerechnet.
im Buch steht nun diese Programmcode;
using namespace std;
int main (void){ char ch; while(true){ cout << " \n>>"; cin.get(ch); if(ch != 'e') cout << ausdruck (ch); else break; } } long ausdruck(char& c) { // übergabe per Referenz long a; // hilfsvariable if (c == '-'){ // - im Eingabestom überspringen cin.get(c); a = -summand(c); // rest an summand() übergeben } if (c == '+'){ cin.get(c); // + überspringen a = summand(c); } while (c== '+'|| c == '-'){ //aufgepasst if(c == '+'){ cin.get(c) // + überspringen a += summand (c); } else { cin.get(c); // - überspringen a -= summand(c); } return a; } // ende von while } // ende der Funktion long summand (char & c){ long s = faktor(c); while (c == '*' || c == '/'){ if (c=='*') { cin.get(c); // * übersprinegn s *= faktor(c); } else { cin.get(c); // / übersprinegn s /= faktor(c); } } // ende der Schleife return s; } // ende der Funktion long faktor(char & c){ long f; if (c == '('){ cin.get(c); // ( übersprinegn f = ausdruck (c); if( c != ')'){ cout << "Rechte Klammer fehlt!\n"; else cin.get(c) ; // ) übersprinegn } else f = zahl (c); return f; } long zahl (char & c) { long z = 0; while(isdigit(c)){ // d.h. c >= '0' && c <= '9' /*isdigit() ist eine Fuktion was zu true ausgewertet wird falls c ein ziffernzeichen ist. Muss #inlcude <cctype> verwenden.*/ z = 10*z + long (c- '0'); cin.get(c); } return z; }
Nun heißt es, dass es den Leser über lassen wird das Programm zum laufen zu bringen, zu vervollständigen, einschließlich trennung von Prototypen und Definitionen.
Mir gelingt dies aber nicht. Könnt ihr mir hierbei bitte helfen und mir nochmal das ganze Prinzip genauer erklären. Danke
Die eigentliche Aufgabe ist es das Programm zum laufen zu bringen
-
aechz123 schrieb:
Das Problem gibts auch in der neueren auflage des buchs. Lade dir doch die loesungen runter (Verzeichnis k3/7), die enthält auch nicht die Abtippfehler.
Das geht leider nicht, da ich nicht die CD besitzte. Das buch ist eigentlich nur ausgeliehen.
-
Die eigentliche Aufgabe ist es das Programm zum laufen zu bringen
-
Schreibe die Prototypen aller Funktionen (außer main) oben hin, damit diese überall bekannt sind. Durch reines Anordnen der Funktionen ist es nicht zu schaffen. siehe: http://www.c-howto.de/tutorial-funktionen-funktions-prototypen.html und http://www2.informatik.uni-halle.de/lehre/c/c_fctord.html
-
Bringe den Code in Ordnung (Klammern, Einrückungen, achte auf die Fehlermeldungen). Klammern im if/else-Bereich gehen nicht auf / stimmen nicht. Für die Suche nach Bugs und das Beheben der Fehlermeldungen des Compilers/Linkers gibt es kein Kochbuch (evtl. google/MSDN-Suche mit der Meldung). Da muss man selbst durch.
-
-
Erhard Henkes schrieb:
- Bringe den Code in Ordnung (Klammern, Einrückungen, achte auf die Fehlermeldungen). Klammern im if/else-Bereich gehen nicht auf / stimmen nicht. Für die Suche nach Bugs und das Beheben der Fehlermeldungen des Compilers/Linkers gibt es kein Kochbuch (evtl. google/MSDN-Suche mit der Meldung). Da muss man selbst durch.
Ja das habe ich jetzt gemacht. Das Programm läuft auch bei mir, aber er gibt bei der Aufgabe (12+3)*4 = 10 aus.
#include <iostream> #include <cctype> // für isdigit() long ausdruck(char& c); long summand (char& c); long faktor (char& c); long zahl (char& c); using namespace std; int main (){ char ch; while(true){ cout << " \n>>"; cin.get(ch); if(ch != 'e') cout << ausdruck (ch); else break; } } long ausdruck(char& c) { // übergabe per Referenz long a; // Hilfsvarinble für Ausdruck. if (c == '-'){ cin.get(c); // - im Eingabestrom überspringen a = -summand(c); // Rest an summand() übergeben } else{ if (c == '+') // + überspringen cin.get(c); a = summand(c); } while (c== '+'|| c == '-'){ //aufgepasst if(c == '+'){ cin.get(c); // + überspringen a += summand (c); } else { cin.get(c); // - überspringen a -= summand(c); } return a; } } long summand (char & c){ long s = faktor(c); while (c == '*' || c == '/'){ if (c=='*') { cin.get(c); // * überspringen s *= faktor(c); } else { cin.get(c); // / überspringen s /= faktor(c); } } return s; } long faktor(char & c){ long f; if (c == '('){ cin.get(c); // ( überspringen f = ausdruck (c); if( c != ')') cout << "Rechte Klammer fehlt!\n"; else cin.get(c) ; // ) überspringen } else f = zahl (c); return f; } long zahl (char & c) { long z = 0; while(isdigit(c)){ // d.h c >= '0' && c <= '9' #include <cctype> z = 10*z + long (c- '0'); cin.get(c); } return z; }
-
Programm zum laufen zu bringen, zu vervollständigen, einschließlich trennung von Prototypen und Definitionen.
Das ist nun erledigt.
Es läuft auch bei mir, allerdings bei Klammerausdrücken fehlerhaft:>>3+5 8 >>7-10 -3 >>(3*5)+1 -2 >>e
Die innere Logik des Programms ist eine andere Baustelle, nämlich deine.
Das nennt man nun Debuggen. Entweder Du verwendest den in der IDE eingebauten Debugger oder Du baust Dir selbst probeweise Ausgaben in die Funktionen ein.
-
wenn ich das mit meinem Compiler übersetze, erscheint die Warnung, dass nicht alle Pfade in der Funktion '
ausdruck
' aufreturn
enden. Nach kurzer Analyse habe ich daraufhin die Zeilen 55 und 57 vertauscht.
Anschließend kam dann nach der Eingabe von (12+3)*4 auch 60 heraus.Gruß
Werner
-
@win87890: Versuche mal selbst diesen Fehler durch Debugging zu finden. Sonst lernst Du hier nichts dazu.
-
Werner Salomon schrieb:
wenn ich das mit meinem Compiler übersetze, erscheint die Warnung, dass nicht alle Pfade in der Funktion '
ausdruck
' aufreturn
enden. Nach kurzer Analyse habe ich daraufhin die Zeilen 55 und 57 vertauscht.
Anschließend kam dann nach der Eingabe von (12+3)*4 auch 60 heraus.Gruß
WernerDanke jetzt Klappt es auch bei mir. Danke du hast mir sehr geholfen
-
Da wäre ich nicht so sicher, ob er Dir wirklich geholfen hat.
-
Erhard Henkes schrieb:
Da wäre ich nicht so sicher, ob er Dir wirklich geholfen hat.
Naja du musst das so sehen. Du hast zuwar vollkommen recht mit der Aussage, dass es besser ist wenn ich den Fehler selber herausfinde. Allerdings war ich schon seit geraumer Zeit auf der Suche nach den Fehler um habe ihn als nicht gefunden. Jetzt weiß ich ja wo der Fehler ist und wenn ich das nächste Mal einen ähnliche Fehler habe werde ich ihn wahrscheinlich selbst finden könnnen. So hätte ich wahrscheinlich noch einige Stunden gesucht. ihn wahrscheilich nicht gefunden. Dann hätte ich das Kapitel "Rekursiver Abstieg" solange ruhen gelassen, bis ich irgendwann einen Fachmann persönlich getroffen hätte, welchen ich dann um hilfe gebeten hätte. Also in guten 3 Wochen.
Ok ich habe zwar noch nicht alles zu 100% verstanden. Aber bin schon in der Lage eine eigenes Programm zu programmieren, welches ähnliche funktionirt, nur nicht ganz so komplix ist. Hierbei rechnet es die Eingabe: 1/4 aus.
Trotzdem Danke, dass du dich mit meiner Frage beschäftigst hast.
-
win8789 schrieb:
Erhard Henkes schrieb:
Da wäre ich nicht so sicher, ob er Dir wirklich geholfen hat.
Naja du musst das so sehen. Du hast zuwar vollkommen recht mit der Aussage, dass es besser ist wenn ich den Fehler selber herausfinde. Allerdings war ich schon seit geraumer Zeit auf der Suche nach den Fehler um habe ihn als nicht gefunden. Jetzt weiß ich ja wo der Fehler ist und wenn ich das nächste Mal einen ähnliche Fehler habe werde ich ihn wahrscheinlich selbst finden könnnen.
Er musste den Fehler noch nciht einmal suchen, sein Compiler hat ihn gewarnt.
Die Lehre, die du daraus ziehen solltest, ist also, alle Compilerwarnungen zu aktivieren.
-
Nathan schrieb:
Er musste den Fehler noch nciht einmal suchen, sein Compiler hat ihn gewarnt.
Die Lehre, die du daraus ziehen solltest, ist also, alle Compilerwarnungen zu aktivieren.Na ja mein Compiler hat mir jetzt keinen Wahrnung angezeigt, obwohl er mir oft einen Wahrnung gibt. Vielleicht sollte ich bei Kompexeren Aufgaben doch lieber Visual Studio 2013 nehmen, anstatt Dev-C++(welches dafür viel unkomplizierter ist und die Erstellung einen Quellcodes geht um einiges schneller).
nachtrag. Gut hab jetzt etwas an den Einstellungen verändert und nun gibt er mir auch einen Wahrnung aus. Danke für den Tipp
-
Du kannst bei Dev-C++ bestimmt auch irgendwo die Compilerflags einstellen. Er verwendet glaube ich GCC oder was kompatibles, da wären mögliche Flags "-Wall -Wextra -Werror -pedantic-errors"
-
Das sind erst einmal nur IDEs, keine Compiler. Aber Dev-C++ nutzt intern standardmäßig den GCC und der GCC ist eigentlich extrem pingelig und zugleich hilfreich, was Warnungen angeht, wenn man die Warnungen aktiviert (Compileroption -Wall, am besten auch noch -Wextra) und wenn man einen halbwegs aktuellen GCC vorliegen hat (Dev-C++ wurde für viele Jahre nicht weiter entwickelt. Ich hoffe, du hast die allerneueste Version und nicht irgendeine von vor 10 Jahren).