[C++] seltsames Verhalten bei cin

L I V E Stammtisch ab 20:30 Uhr im Chat
  • Mahlzeit zusammen.

    Ich beschäftige mich gerade mit C++

    Ich habe hier das Buch "Einführung in die Programmierung mit C++"

    Die aktuelle Übung bezieht sich auf switch und if Anweisungen.

    Man sollte einen kleinen Währungsrechner programmieren.

    Soweit läuft das Programm auch erstmal wie es soll, außer der Nutzer gibt als ersten den Betrag direkt gefolgt von einem 'e' oder 'E' (für Euro) ein, also z.B. 100e oder 23E.

    Für alle anderen Währungen geht das (die Kürzel sind D,P,J,C,K), also z.B. 42K oder 129d.

    Meine Vermutung ist, dass das e oder E in dem Fall für die Expotentialdarstellung rangezogen wird und das ganze nen Fehler verursacht.

    Ich habe hier das include <iostream> und den namespace std für euch eingefügt, ich nutzte die auskommentierte headder Datei, aber die gehört speziell zum Buch und die hier genutzten Teile sind alle auch in iostream.

    Kann mir wer erklären wo das Problem liegt?

    Hier mal der Code:

  • Na ja, cin ist ohnehin seltsam...

    So kann man den Fehler detektieren:

    Der Fehler wird bei der Waehrung angezeigt, aber er passiert schon beim Einlesen von Betrag, weil das noch eine Zahl hinter dem e erwartet.

    1e0e geht durch.

  • Ein sicherer Weg, die Unterscheidung fehlerunanfällig durchzuführen, ist, das vorletzte Zeichen des Eingabestrings abzufragen und dieses den Switch durchzuführen. In C (da C++ als Menge betrachtet C als Teilmenge (nahezu) vollständig beinhaltet; daher auch in C++) werden Strings als Arrays behandelt, daher ist eine gute Herangehensweise, erstmal die Stringlänge zu bestimmen (<string.h> wird benötigt):

    Anschließend wird in diesem Code-Beispiel das vorletzte Zeichen abgefragt, da dieses den Buchstaben enthält, auf den Sie "switchen".

    Der Vollständigkeit halber:

    C zählt das erste Arrayelement als "0" und legt in das letzte Element das Stringende-Zeichen ("\0"), weshalb ein String der Länge 3 tatsächlich nur zwei beliebige Elemente enthält, das Nullte und das Erste, auf dass geswitcht wird.

    Ich weiß, ich habe jetzt nur für C gesprochen, aber da C++ aus selbigem hervorgegangen ist (siehe oben), bin ich mir sicher, dass dies auch unter C++ funktioniert.

  • Zorosol

    Gute Idee, nur müsste ich dann alles als ein String einlesen, mit dem letzten Char im String switchen und den Rest vom Array abtrennen und in einen double umwandeln. Und sobald ein Nutzer z.B. '120 e' hätte ich wieder Probleme denn array[2] wäre in dem Fall die '0'.

    Ich hatte mir das Problem heute nochmal auf der Arbeit mit einem Kollegen angeschaut (der mich für bescheuert erklärte weil das ja nur ein Übungsprogramm ist). Aber uns ich auch zusammen keine wirklich schöne Methode eingefallen. Das einfachste wäre wohl die Abfrage nach dem Betrag und nach der Währung zu trennen.

    Linus

    Danke, dass schaut gut aus.

    Aber damit komme ich aktuell auch noch nicht so wirklich klar. Ich kann zwar grob nachvollziehen was da steht, aber halt nur grob.

    Und ohne genaueren Verständnis was da steht und was da passiert frickel ich da nichts in meinen Code, weil das meiner Art zu lernen bzw etwas zu machen widerspricht.

    Dank Dir trotzdem für deine Mühen.

  • Zorosol:

    int a = strlen(string);
    switch(string[(a-2)]

    da solltest Du auf alle Fälle unbedingt noch auf a < 2 abfragen (wobei ausserdem die 2 als Konstante definiert sein sollte) ...

    Mario Be:

    wenn dieser Spaghetti-Code mit goto ernsthaft so in einem C++ Lehrbuch steht, würde ich an Deiner Stelle ganz schnell die Lektüre wechseln ...

    cu,

    -ds-

  • Für mich hat das Programm in der aktuellen Fassung einen grundlegenden Designfehler was die Ermittlung der Umrechnung betrifft.

    Zunächst hast Du für jede mögliche Kombination für die umzurechnenden Währungen je eine Konstante definiert. Bei Deiner recht übersichtlichen Zahl an verschiedenen Währung kann man das gerade noch so hinnehmen, im Hinblick auf den Ausbau auf weitere Währungen ist das aber eine Sackgasse, weil die # Kontanten deutlich schneller wächst als die # Währungen. Ferner baust Du redundante Informationen in den Sourcecode ein.

    Besser wäre es hier, ein Array mit Kursverhältnissen relativ zu einer Referenzwährung anzulegen. Als Referenzwährung kannst Du an Position 0 den € nehmen und diesen mit 1 belegen (€ zu € ist 1) und dann die anderen Währungen im Verhältnis zum € ergänzen. Damit wächst die Datenbasis exakt gleich mit der # Währungen mit und es gibt keine Redundanten Informationen mehr.

    Aus dem Designfehler mit den vielen Konstanten folgen dann die vielen if-Abfragen in den switch-Statements. Hier ist zu erkennen, dass eine angemessene Wartbarkeit des Sourcecodes schon nicht mehr wirklich gegeben ist.

    Wie nun anders bzw. besser vorgehen?

    Nachdem Du den Betrag, die Quell- und die Zielwährung ermittelt hast, brauchst Du nur noch herausfinden, an welcher Position in dem eingangs erwähnten Array sich die Quell- und die Zielwährung befindet. Dann lautet die Berechnung zur Umrechnung recht einfach:

    <Betrag der Zielwährung> = <Betrag der Quellwährung> / <Kursverhältnis der Zielwährung> * <Kursverhältnis der Quellwährung>

    Du kannst mit einer Tabellenkalkulation recht schnell ausprobieren, wie das Prinzip dahinter aussieht.

    Mit dem beschriebenen Verfahren wird Redundanz vermieden und Wartbarkeit des Sourcecode erhöht.

  • So viel Durchhaltevermoegen muss belohnt werden:

  • Und sobald ein Nutzer z.B. '120 e' hätte ich wieder Probleme denn array[2] wäre in dem Fall die '0'

    An sich ist dies richtig, jedoch meinte ich array[(strlen(array))-(2)]nicht array[2] –, was in jedem Fall das Währungszeichen abfragt, da dieses immer das letzte ist, was der User dem Programm übergibt. Dieses Detail hatte ich auch erwähnt:

    Zitat von Mario Be

    Gute Idee, nur müsste ich dann alles als ein String einlesen, mit dem letzten Char im String switchen und den Rest vom Array abtrennen und in einen double umwandeln.

    Es ist sicherer, die Eingabe erst als String zu behandeln, da so potentielle Eingabefehler herausgefiltert werden können – beispielsweise durch Überprüfung der ASCII-Nummer des Zeichens. Der Nutzer muss sich nicht an die Vorgaben halten, es ist seine freiwillige Entscheidung. Was passiert beispielsweise bei 327856h734837 y? Eigentlich müsste das Programm abstürzen. Um dies eben zu verhindern, lohnt es sich, die Stringvariante zu nutzen.

    Außerdem, wenn es eine Übung eines Lehrbuches ist, müsste eigentlich eine Lösung irgendwo drinstehen; bei Rheinwerk Computing meistens als Anhang.

  • Tell

    Das Buch ist nicht vom Rheinwerk, sondern von Pearson, ich hab mich für "Einführung in die Programmierung mit C++" vom Stroustrup entschieden.

    Bin halt noch sehr am Anfang. Strings und Arrays werden ja später noch weiter behandelt. Komme leider mit dem Buch aus zeitlichen Gründen nicht so vorran wie ich es gerne hätte.

    Hab privat parallel noch PHP7 und Vertiefung in HTML5 und CSS3 auf dem Programm, und dass neben dem ganzen Lernstoff der Umschulung.

    Die Lösung ist noch sehr rudimentär. Da werden erstmal Fehleingaben noch gar nicht abgefangen.

    Wir sind noch bei dem Punkt, wo die Nutzer genau wissen was sie machen, also Du weißt schon, diese Nutzergruppe aus Utopia ;)

  • Eine Bemerkung am Rande, die fast schon offtopic ist:

    Dein Sourcecode hat mit C++ nicht rasend viel zu tun, Du bist viel dichter an C dran als an C++. Konkretes Beispiel ist Dein Nichtverwenden der String-Klasse. Stattdessen bist Du mit arrays unterwegs. Das ist per se erst einmal kein Fehler denn diese Art der Verwaltung von Zeichenketten ist ja in C++ nicht explizit ausgeschlossen. Ist aber eben auch kein C++-Stil und damit verbaust Du Dir auf lange Sicht die Chance, die Stärken von Klassen bzw. von Objekten auszureizen.

    Da ich ja Dein Lernziel nicht genau kenne, kann ich auch nicht sagen, ob Du eventuell eine komplette Neujustierung Deiner Arbeitsweise brauchst. Oder anders ausgedrückt: Zurück auf Los und Neustart.

    Eine Empfehlung wäre noch, dass Du mal in Youtube nach Tutorials schaust. Die Perlen zu finden ist nicht einfach aber ich habe auch dort für mich was gefunden, was gerade den "Umstieg" von C nach C++ für mich etwas erleichtert hat.

    Vielleicht ist es etwas zu pessimistisch, aber lass Dir gesagt sein: die ersten 10.000 Zeilen Sourcecode sind alle Mist - danach fängt es an Spaß zu machen und raketenstarke Programme kommen dann dabei heraus! Nicht aufgeben, weitermachen!!

  • peuler

    Ja, Klassen und OOProgrammierung kommt noch im Buch.

    Wie gesagt, sind noch die reinen Grundkonstrukte und die Programme bzw Übungsaufgaben sind eher noch prozedurale Programmierung.

    Aber recht hast Du auf jeden Fall, es sind verdammt viele Zeilen Code und verdammt viele Fahler nötig um Programmieren zu lernen.

    Tutorials bei YT will ich mir aktuell nicht anschauen, ich will erstmal das Buch durcharbeiten. Das wird ja an vielen Stellen empfohlen, zur Ergänzung habe ich hier noch "C++ Das umfassende Handbuch" vom Rheinwerk Verlag. Da schlage ich dann die Sachen, die im Buch vom Stroustrup beschrieben werden nochmals nach. Das hat den Grund, dass das Buch nicht ganz aktuell ist und in dem vom Rheinwerk die '17er Notation dabei ist.

    Ich werde mich bei den nächsten Aufgaben aber wirklich einfach an die Vorgaben vom Buch halten und keine solche Spielereien mehr versuchen.

    Ich hab gestern noch etwas durch das Buch quer gelesen und mal so die folgenden Kapitel überschlagen. Um Fehleingaben etc geht es später wohl noch ganz explizit.

  • Der C++ Standard in der Version 17 ist der aktuelle. Es wird gerade an einer Verison 20 gearbeitet, aber dieser kommt nach Plan eben erst 2020 raus. Selbst Wenn das Buch nur die Version 14 oder gar nur 11 abdecken sollte, ist das für einen Einsteiger immer noch eine enorm hohe Hürde. Keine Sorge, Du hast die aktuelleste Fassung vorliegen, genau die gleiche habe ich mir Ende letzten Jahres bestellt, weil sie auch erst Ende 2017 im Rheinwerk-Verlag erschienen ist.

  • Ja, darum habe ich mir das Handbuch ja noch zur Ergänzung gekauft.
    Ich meine das Buch vom Stroustrup ist schon sehr gut, und der Kerl sollte wissen was er da schreibt, der hat ja C++ nunmal erfunden.
    Aber weil dort die aktuellste Auflage von 2010 ist, dachte ich was aktuelles dazu könnte nicht schaden.
    Ok, da wo ich z.Z. bin hat sich noch nichts wirklich geändert. Aber ein Bekannter der recht sicher in C++ ist meinte, dass sich gerade mit 2014 und 2017 doch einiges getan hat.

    So, nun muss ich aber weiter Taschen Packen und das Fahrrad beladen, werde morgen nach der Schicht mit den Kinder campen fahren, brauche mal ein Bit und Technik freies Wochenende.

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!