Programm reagiert bei Buchstabeneingabe komisch

IZZO

Mitglied
Moin, ich bin ganz neu bei C++ und stehe vor einem Problem. Mein Programm spuckt plötzlich unendlich lange, den gleichen Satz aus, doch guckt selber.

C++:
#include <iostream>
using namespace std;

int eingabe_auswahl;
float zahlen[3];

int main() {
    marke:
    cout << "Grundwert:   1\n";
    cout << "Prozentwert: 2\n";
    cout << "Prozentsatz: 3\n";

    cin >> eingabe_auswahl;

    if(eingabe_auswahl == ( 1 || 2 || 3 )){

    switch(eingabe_auswahl){
        case 1: cout <<"Geben Sie den Prozentwert ein und bestätigen mit Enter. Verfahren Sie genauso mit dem Prozentsatz (in %).\n";
                cin >> zahlen[0];
                cin >> zahlen[1];
                zahlen[1] = zahlen[1] / 100;
                zahlen[2] = zahlen[0] / zahlen [1];
                cout << "Mit einem Prozentwert von " << zahlen[0] << " und einem Prozentsatz von " << zahlen[1] * 100
                     << "% ergibt sich ein Grundwert von " << zahlen[2] << ".\n";
        break;

        case 2: cout <<"Geben Sie den Grundwert ein und bestätigen mit Enter. Verfahren Sie genauso mit dem Prozentsatz (in %).\n";
                cin >> zahlen[0];
                cin >> zahlen[1];
                zahlen[1] = zahlen[1] / 100;
                zahlen[2] = zahlen[0] * zahlen [1];
                cout << "Mit einem Grundwert von " << zahlen[0] << " und einem Prozentsatz von " << zahlen[1] * 100
                     << "% ergibt sich ein Prozentwert von " << zahlen[2] << ".\n";
        break;

        case 3: cout <<"Geben Sie den Prozentwert ein und bestätigen mit Enter. Verfahren Sie genauso mit dem Grundwert.\n";
                cin >> zahlen[0];
                cin >> zahlen[1];
                zahlen[2] = zahlen[0] / zahlen [1];
                cout << "Mit einem Prozentwert von " << zahlen[0] << " und einem Grundwert von " << zahlen[1]
                     << " ergibt sich ein Prozentwert von " << zahlen[2] * 100 << "%.\n";
        break;
    }

    }


    else{
        cout << "Bitte geben Sie die Zahlen '1 für Grundwertberechnung', '2 für Prozentwertberechnung' "
                "oder '3 für Prozentsatzberechnung' ein.\n\n";
        goto marke;
    }


    cin.sync();
    cin.get();
    return 0;
}

Ich denke, dass Problem liegt in der else-Anweisung. Wenn ich eine falsche Zahl eingebe (>3 und <1), reagiert das Programm so wie es sollte. Nur bei einer Buchstabeneingabe funktioniert es nicht. Habs auch schon mit try/catch probiert (vllt falsch?).
 
Hi

ob die Eingabe zumindest eine gültige Zahl war kann mit if(cin.good()) geprüft werden (nach dem Einlesen der Zahl, vor der nächsten cin-Verwendung). Und das if mit eingabe_auswahl so abzukürzen geht nicht, es muss so ausschauen:
C++:
if(eingabe_auswahl == 1 || eingabe_auswahl == 2 || eingabe_auswahl == 3)
oder auch
C++:
if(eingabe_auswahl >= 1 && eingabe_auswahl <= 3)
 
Zuletzt bearbeitet:
Noch kurz zur Erklärung was die Zeile macht:
if(eingabe_auswahl == ( 1 || 2 || 3 ))

1, 2 und 3 bekommen booleans gemäss der folgenden Regel (§4.12 - Boolean Conversions):
A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true.

also:
if(eingabe_auswahl == (true || true || true))
bzw:
if(eingabe_auswahl == true)

Was hier passiert ist folgendermassen geregelt (§4.7 - Integral Conversions):
If the destination type is bool, see 4.12. If the source type is bool, the value false is converted to zero and the value true is converted to one

Also in dem Fall:
if(eingabe_auswahl == 1)

Als kleiner Einwurf weil viele Leute oft nicht bedenken, wie bool <-> int Konvertierungen funktionieren.

Das ist auch der Grund warum folgender Code:
if(2 == (1 || 2 || 3))

nicht das gewünschte Ergebnis lieft. 2 wird nicht in true umgewandelt sondern im Endeffekt steht da if(2 == 1). Das ist der Grund warum z.B. Visual Studio sich da beklagt:
warning C4806: '==' : unsafe operation: no value of type 'bool' promoted to type 'int' can equal the given constant

Viele Grüsse
Cromon
 
Hallo IZZO,
ich hätte auch noch 3 kleine Bemerkungen, die nicht direkt was mit deiner Frage zu tun haben, aber dir sicherlich weiterhelfen werden ;).
Der Anfang deiner Code-Datei sieht so aus:
Code:
#include <iostream>
using namespace std;
int eingabe_auswahl;
float zahlen[3];
int main() {
.
.
.
Du solltest using namespace std; nicht global verwenden. Im Zuge der "Clean Code"-Welle die vor ein paar Jahren die Runde gemacht hat, verwenden die meisten Entwickler heute gar kein using mehr. Heute schreibt man meist überall das std:: davor. Wenn du lieber das using verwenden möchtest, dann schreibe es bitte immer nur in den Funktionen ganz oben hin, in denen du es auch brauchst, also in deinem Fall ganz oben in die main().
Darunter legst du zwei globale Variablen an. Globale Variablen sind immer böse. Da du schreibst dass du noch ganz neu bei C++ bist, erspare ich dir hier mal die Details, aber glaub mir bitte dass sie böse sind, und du - so gut es geht - darauf verzichten solltest. Da du eingabe_auswahl und zahlen[] sowieso nur in der main() verwendest, kannst du sie auch dort deklarieren.
Das Wichtigste finde ich aber, ist das goto in Zeile 51. Niemals goto verwenden. Ich weiß, dass C++ dieses Schlüsselwort besitzt, und als ich noch Anfänger war habe ich es sogar ab und zu verwendet. Aber goto ist böse! Es ist der Tod eines sauberen Programmflusses! Niemals verwenden!
In vielen Jahren der Programmierung ist mir noch nie ein Fall untergekommen, bei dem ich goto wirklich gebraucht hätte. Es gibt immer eine bessere, eine lesbarere Methode um eine Routine zu realisieren.
In deinem Fall benutzt du goto, um innerhalb deines Programmes eine Schleife einzubauen (um so lange die Abfrage weiterzuführen, bis ein korrekter Wert ausgelesen wird).
Frage: Wieso verwendest du nicht einfach eine Schleife? Ich habe für dich den Programmteil, der die Eingabe ausliest mal in eine Funktion gekapselt und den Code etwas umgeschrieben, so dass er ohne goto auskommt. Das ist wesentlich sauberer und angenehmer zu lesen:
Code:
#include <iostream>
#include <limits> // for std::numeric_limits

int eingabeAbfragen(); // prototype
int korrekteAuswahl(); // prototype

int main()
{
    int eingabe_auswahl = korrekteAuswahl();
    switch (eingabe_auswahl) {
    case 1:
        std::cout << "Blubb 1" << std::endl;
        break;
    case 2:
        std::cout << "Blubb 2" << std::endl;
        break;
    case 3:
        std::cout << "Blubb 3" << std::endl;
        break;
    }
    // mach was
    return 0;
}


int eingabeAbfragen()
{
    std::cout << "Gundwert:    1" << std::endl
              << "Prozentwert: 2" << std::endl
              << "Prozentsatz: 3" << std::endl;
    int auswahl;
    std::cin >> auswahl;
    if (!std::cin.good()) {
        return -1;
    } // else continue
    if (auswahl < 1 || auswahl > 3) {
        return -1;
    } // else continue
    return auswahl;
}
int korrekteAuswahl() {
    int eingabe_auswahl = -1;
    while (eingabe_auswahl == -1) {
        eingabe_auswahl = eingabeAbfragen();
        if (eingabe_auswahl == -1) {
            std::cout << "Die Eingabe war ung" << (char)129 << "ltig!" << std::endl;
        }
        if (std::cin.fail()) { // check if stream is good before repeating
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
    }
    std::cout << "Die Eingabe war g" << (char)129 << "ltig." << std::endl;
    return eingabe_auswahl;
}
Normalerweise würde man die einzelnen cases auch noch in Funktionen kapseln, aber ich habe mir das jetzt mal geschenkt :).
Ich denke, wenn du die Tipps berücksichtigst, sparst du dir selbst später mal viel Ärger.
Grüße Technipion
 
Zurück