Fehlersuche in kleinem Programm
-
Ist das so schlimm?
Naja, über Stil kann man sich endlos streiten. Das Hauptprogramm ist intuitiv fast unleserlich. Warum so ein Aufwand, wenn nichts bei rum kommt?
-
Erhard Henkes schrieb:
Ist das so schlimm?
Naja, über Stil kann man sich endlos streiten. Das Hauptprogramm ist intuitiv fast unleserlich. Warum so ein Aufwand, wenn nichts bei rum kommt?
konkret?
wie gesagt mehr kann ich (noch) nicht
-
Skyese schrieb:
Erhard Henkes schrieb:
Ist das so schlimm?
Naja, über Stil kann man sich endlos streiten. Das Hauptprogramm ist intuitiv fast unleserlich. Warum so ein Aufwand, wenn nichts bei rum kommt?
konkret?
wie gesagt mehr kann ich (noch) nicht
Was er meint ist wahrscheinlich für einen Anfänger noch schwer zu verstehen.
Es geht darum, dass man nicht so recht weiss, was du in deinem Code willst.

Aber ich finde das jetzt noch nicht so tragisch, weil du das früher, oder später selber merken wirst, dass, was du da machst eigentlich völlig sumoptimal ist.Aber etwas wichtiges, was dein Codingstyl beeinflusst ist dir bereits passiert. Du weisst selbst nicht so recht, was dein Programm macht. Dein Code had die überhand über die gewonnen und das ist etwas, was eine Programmierer NIE passieren darf.
Sprich. Strukturier dein Code besser (Klassen), benne alles einheitlich und klar ersichtlich so, dass du immer genau weisst, was die Funktion macht und was sicher nicht passieren darf.Also am besten probierst du jetzt da mal mit dem Debugger dein Problem zu finde, wenn das nicht klappt, schreibst du das Programm neu und dann schön Stück für Stück, dass du immer weisst, was genau passiert usw.
Wenn das auch nicht hinhaut. Mach ein anderes Beispiel und/oder lerne mal schön weiter. Dann schau dir den Code so in 1-2 Monaten an und dir wird das grauen kommen.
-
drakon schrieb:
Sprich. Strukturier dein Code besser (Klassen)
Er kennt Klassen glaub ich noch nicht ;). Vorläufig geht das auch ohne, in ein paar Monaten kann er ja immer noch einen Klassen-Taschenrechner programmieren.
@ Skyese:
Den anderen Ratschlägen von drakon kann ich aber nur zustimmen. Kommentier deine Funktionen und Zeilen, nimm erst mal einige Dinge weg, und schau, ob es überhaupt ansatzweise läuft. Wenn du dich mit dem Debugger noch nicht genau auskennst, kannst du dir auch Variablen perstd::coutan verschiedenen Stellen ausgeben lassen (der Debugger ist später trotzdem unersetzlich).Ich finde dein Programm jedoch relativ lesbar. Okay, teilweise sind die Einrückungen und Abstände nicht gerade optimal, aber wenn man das mit anderen Taschenrechnern vergleicht... Du bist auf dem guten Weg

Merk dir am besten, dass du nach jeder öffnenden geschweiften Klammer zu Beginn eines Blocks eine Einrückung machst, das ist am übersichtlichsten. Und die { würd ich am besten immer auf eine neue Zeile setzen, was du z.B. beido {nicht gemacht hast.Etwas, was mir beim Überfliegen aufgefallen ist:
Weiter() // <- welcher Rückgabetyp? Auch int-Rückgabetypen muss man in C++ explizit angeben. { ...Noch was:
(char)129Das nennt man C-Style-Cast. Ist im Moment vielleicht noch vertretbar, allerdings weiss man dabei nie genau, was passiert. Nimm lieber
static_cast<char>(129), auch wenn es länger ist.
-
Nexus schrieb:
Er kennt Klassen glaub ich noch nicht
Das ist richtig, das ist das nächste Kapitel.

Nexus schrieb:
Kommentier deine Funktionen und Zeilen
Also ehrlichgesagt, das was Drakon vorhin geschrieben hat, dass ich selber nicht mehr so recht weiss was der Code macht, das stimmt nicht ganz

Bei diesem Quelltext wusste ich so ziemlich alles was wo ist und was es macht, deshalb vertand ich den Fehler nicht.
Kommentieren tu ich meist auch, gestern habe ich Funktionen aber zum ersten Mal im "grossen" Stil angewendet, ich wusste zuerst noch gar nicht was genau passiert, dies sah ich erst wirklich bei der Ausführung, die Kommentare kann ich jetzt immer noch schreiben...
Nexus schrieb:
Ich finde dein Programm jedoch relativ lesbar.
Noch eine Frage dazu: mir wurde in einem anderen Forum mal gesagt ich soll den Funktionsrumpf immer oberhalb der Main() schreiben, ich fand es zuerst aber unterhalb der Main() etwas Übersichtlicher, wie macht ihrs denn?

Nexus schrieb:
Das nennt man C-Style-Cast. Ist im Moment vielleicht noch vertretbar, allerdings weiss man dabei nie genau, was passiert. Nimm lieber
static_cast<char>(129)Danke für den Tipp, darf ich aber noch wissen was es genau macht im vergleich zum 'kurzen' Befehl?
Noch nebenbei:
Hab das Problem gelöst
Ich habe in der Weiter()-Funktion goon zweimal abgefragt, nahm die erste Abfrage in der goon==1-Schleife weg und siehe da es funktioniert :pEDIT: Was ich noch fragen wollte: Ich habe Code::Blocks, wenn ich dort mal einen Quelltext gespeichert habe, wieder lade, abändere und komiliere... dann kompilierter sich zwar, was ich aber seit der Speicherung neu geschrieben habe übernimmt er nicht.. Weiss jemand wieso?

Vielen Dank für eure Hilfe Leute

-
Skyese schrieb:
Noch eine Frage dazu: mir wurde in einem anderen Forum mal gesagt ich soll den Funktionsrumpf immer oberhalb der Main() schreiben, ich fand es zuerst aber unterhalb der Main() etwas Übersichtlicher, wie macht ihrs denn?

Das kannst du eigentlich machen, wie du willst. Ich würd sie vorher definieren. Wenn die Funktionen nach
main()kommen, müssen sie vorher noch deklariert werden:double Rechnung(double Zahl1,char Operat,double Zahl2);Später wirst du Funktionen wahrscheinlich in eine Headerdatei auslagern, und dann kommen sie auch vor der
main().Skyese schrieb:
Danke für den Tipp, darf ich aber noch wissen was es genau macht im vergleich zum 'kurzen' Befehl?
Die Version mit den Klammern probiert auf irgendeine Art und Weise, den Datentyp umzuwandeln.
static_castdagegen überprüft zur Compilezeit (deshalb static_cast), ob für die Typumwandlung eine vorgesehene Konvertierungsmöglichkeit besteht. Wenn nicht, wird eine Fehlermeldung ausgegeben. Die C-Version ist hierbei viel unsicherer, weil sie notfalls auch den Speicherbereich komplett neu interpretiert. Wenn du das tun willst, gibt es in C++reinterpret_cast, aber das braucht man normalerweise selten.Skyese schrieb:
Hab das Problem gelöst

Sehr schön, geht doch. Auf zum nächsten Kapitel

-
Nexus schrieb:
Das kannst du eigentlich machen, wie du willst. Ich würd sie vorher definieren. Wenn die Funktionen nach main() kommen, müssen sie vorher noch deklariert werden
Ich hab anfangs auch nur die Deklaration gemacht, den Rumpf nach der Main(), habe es jetzt mal oben gemacht aber habe es eben wie gesagt unübersichtlicher gefunden...
Wenn ich die Funktion dann wahrscheinlich sowieso in eine Headerdatei (Ähh was??
) auslagere behalte ich es aber jetzt so bei, THX für deine Erklärung, hat mir geholfen 
-
Was mir noch aufgefallen ist:
Wenn du in switch-konstrukten return verwendest kannst du dir das break danach sparen, denke ich mal.
-
@ Skyese:
Es ist nicht generell so, dass man Funktionsdefinitionen in Headern (Dateien mit Endung .h oder .hpp, die man einbinden kann) auslagert. Bei der modularen Programmierung mit mehreren CPP-Dateien ist es eher so, dass Deklarationen im Header und Definitionen in der CPP-Datei stehen. Aber das musst du vorläufig eigentlich nicht beachten, das ist eigentlich erst bei grossen Projekten relevant
Die Funktionen vor der
main()-Funktion zu definieren, hat den Vorteil, dass du Deklaration und Definition in einem hast und immer schön zuunterst anmain()weiterarbeiten kannst.Noch was zum Stil: Ich würd mir angewöhnen, immer schön Abstände zu machen, das steigert die Übersicht enorm.
Stattdo{ // ... }while(rplay==2); Rechnung(Zahl1,Operat,Zahl2);schreibst du dann
do { // ... } while (rplay == 2); Rechnung(Zahl1, Operat, Zahl2);Aber schlussendlich ist das natürlich Geschmackssache und jedem selber überlassen, aber ich würds dir empfehlen...
-
Er kennt Klassen glaub ich noch nicht ;). Vorläufig geht das auch ohne, in ein paar Monaten kann er ja immer noch einen Klassen-Taschenrechner programmieren.
Das war mir klar, darum meinte ich ja, dass er lieber auch einfach mal weitermachen soll, dann kommt das von alleine.
Also ehrlichgesagt, das was Drakon vorhin geschrieben hat, dass ich selber nicht mehr so recht weiss was der Code macht, das stimmt nicht ganz

Bei diesem Quelltext wusste ich so ziemlich alles was wo ist und was es macht, deshalb vertand ich den Fehler nicht.
Kommentieren tu ich meist auch, gestern habe ich Funktionen aber zum ersten Mal im "grossen" Stil angewendet, ich wusste zuerst noch gar nicht was genau passiert, dies sah ich erst wirklich bei der Ausführung, die Kommentare kann ich jetzt immer noch schreiben...

Scheint so, als ob ich doch Recht hatte.
Es war auch kein Vorwurf. Das passiert schonmal, dass man meint, dass man etwas richtig überlegt hat und überzeugt ist, dass es so funktionieren muss, aber man dann beim ausführen merkt, dass es doch nicht so ganz das ist, was man wollte.Du solltest deinen Code einfach so weit im Kopf haben, dass du, wenn etwas passiert du sofort weisst, wo du in etwa suchen musst. Sprich, wenn du siehts, dass irgend etwas mit der Eingabe nicht funktioniert du genau an eine Stelle gehen musst (wo die Eingabe statt findet) und dann an dieser Stelle gezielt (mit dem Debugger) schauen kannst, was da anderst läuft, als du dir das vorstellst. Dann überlegst du dir einfach jeden Schritt ganz genau, was du erwartest, dass gemacht wird und dann schaust du, WAS gemacht wird. Wenn deine Behauptunt und der Fall, der Eintritt unterschiedlich sind, bist du schon fast am Ziel und hast den Fehler gefunden.
-
Der Debugger macht mich langsam neugierig

Nächste oder übernächste Woche werde ich zu ihm kommen, wenn ich mich jeden Tag reinhänge

Hmmm.. da hab ich mich doch vorher tatsächlich im selben Satz widersprochen
, naja wenigstens grösstenteils wars verstanden 
-
naja so wie du das bis jetzt gemacht hast ist das eig schon relativ gut für einen anfänger
aber eine sache hätte ich noch:
du hast noch nicht ganz verstanden wozu funktionen eigendlich da sind
Skyese schrieb:
double ErsteZahl() { double Zahl; cout << endl << endl << "Geben Sie nun eine Zahl ein: "; cin >> Zahl; return Zahl; } double ZweiteZahl() { double Zahl; cout << endl << endl << "Geben Sie nun eine weitere Zahl ein: "; cin >> Zahl; return Zahl; }was fällt dir an diesen beiden funktionen auf?
richtig, sie machen im prinzip dasselbe
sie fragen beide anch einer zahl und returnen diese dann...an deiner stelle würde ich das dann zu folgendem zusammensetzen
double ZahlAbfragen() { double Zahl; cout << endl; cout << "Gib eine Zahl ein: "; cin >> Zahl; return Zahl; }dann könntest du in der main funktion folgendes schreiben
int main() { // ... double zahl1, zahl2; zahl1 = ZahlAbfragen(); zahl2 = ZahlAbfragen(); }das alles in eine funktion zu packen hat folgende vorteile:
- weniger schreibarbeit, und damit weniger syntaktische fehler
- weniger logische fehler weil alles ja nur einmal geschrieben werden muss
- kleinere programme, sowohl vom quellcode als auch vom späteren mashcinencode her
- bessere lesbarkeit, man muss beim durchgehen nur eine funktion im kopf haben und sich halt nur eine funktion kurz angucken, anstatt 2du hast die funktionen alle als textersetzung geschrieben
nach dem motto: 5 zeilen hauptprogramm, aber noch 80 zeilen funktionenalso denk dran:
-schreibe funktionen immer so dass du sie möglichst oft wieder verwenden kannst
-lass eine funktion absolut nur das machen was sie soll (im späteren verlauf beeinhaltet dass sogar dass du in einer funktion soger für eine "einfache" ausgabe schon eine andere funktion wieder aufrufst -> stichwort: streamumleitung)mfg mosho
PS: du hast ja in beiden funktionen 2 verschiedene text anchrichten an den benutzer eingebunden, sowas kann man dann realisieren wenn man eben die gewünschte nachricht an die funktion übergibt, aber das sollte dir bald auch klar werden...
-
Da geb ich dir völlig recht, das war wohl ein Denkfehler. Mir ging es nämlich - wie du gesagt hast - darum, dass die Sätze gleich sind. Dass hätt ich anders lösen können, das stimmt, werd ich mir merken

Skym0sh0 schrieb:
du hast die funktionen alle als textersetzung geschrieben
nach dem motto: 5 zeilen hauptprogramm, aber noch 80 zeilen funktionenEben, wie ich bereits gesagt hab ist der Aufbau ein völliger blödsinn :p aber eben ich wollte damit lediglich den Aufbau von Funktionen lernen und dass war nur möglich wenn ich möglichst viel Funktionen mache auch wenns keinen Sinn hat.

Dafür sieht der Code unterhalb der Main() recht übersichtlich aus

-
jop da haste recht^^
naja viel spass und erfolg noch in der (C++)-Programmierung...
Und ich denke dass du erfolg haben wirst...
-
Danke, das hoff ich auch (und glaube das kann ich auch, was ich mir in den Kopf gesezt habe will ich!
)Gerade Pointer, Arrays durchgemacht und jetzt bei den Strings

ziemlich happig, aber das kommt gut
-
also die strings sind einfach
also ich meine die klasse damit
ist quasi wie im (noob)-java
relativ einfach...pointer sidn an sich auch nicht schwer aber man muss irgendwie immer etwas um die ecke denken
und da muss man sich etwas dran gewöhnenarrays sind ganz einfach, aber nach kurzer zeit sind das eig auch schon nur noch pointer auf sonstwas...
-
Für was sind die Arrays eigentlich, der wirkliche Nutzen wird in meinem Buch nicht erklärt, auch im Internet ist auf die schnelle kein konkretes Beispiel zu finden...

Ist es für Grafikberechnungen??

Morgen ist ja eh wiedermal ein repeat-day^^
-
Arrays sind quasi starre Container für beliebige Datentypen. Du kannst also zum Beispiel die monatlichen Umsätze von einem Unternehmen als long speichern ohne das du 12 Variablen anlegen musst und wenn du dann zum Beispiel den Umsatz vom Februar willst kannst du über den Index 1 darauf zugreifen (weil ja bei 0 angefangen wird zu zählen).
MfG
-
OK danke für deine Antwort, ist mir jetzt schon klarer

-
arrays sind auf gut deutsch ein speicher für einen datentyp mit einer bestimmten grösse
für manche probleme (primzahlberechnung per brute force oder wahrscheinlichkeiten bzw mittelwerte) braucht man halt 10000 zahlen um es zu lösen
ja und man könnte jetzt 10000 variablen einzeln erstellen
oder eben arrays benutzen:int a1, a2, a3, a4, ..., a10000; // 10000 einzelne variablen int a[10000]; // ein array mit 10000 speicherplätzen