Programmabsturz bei Buchstabeneingabe in Integerfeld



  • Hallo Leute,

    ich bin neu hier im Forum (habe erst einen Thread eröffnet, der optimal betreut wurde) und habe folgendes Problem:

    Ich habe ein Feld (spielfeld) als Integer deklariert und speise in dieses Werte ein. Es dürfen nur 0en und 1en eingelesen werden. Wie ich einen Abbruch mache, wenn andere Zahlen eingegeben werden, habe ich herausgefunden, aber wie breche ich ab, wenn ein Buchstabe eingegeben wird? Ich lande dann immer in einer Endlosschleife, die ich nur durch STRG+C beenden kann. Bisher habe ich einfach den Typ auf Character geändert, aber das ist wohl erstens nicht die sauberste Art und zweitens muss ich dieses mal mit den Werten weiter rechnen, was mit Charactern wohl schwierig wird.

    cin >> spielfeld[i][k];
            			if (spielfeld[i][k] != 0 && spielfeld[i][k] != 1){
    						cout << endl << endl;
    						meldung (sprache, id = 5); //Meldung 5 Nur 0 und 1 gültig
                            cout << endl;
    						fehler = true;
    						break;
            			}
          			}
          			if (fehler){
          				break;
    				}
    

    Das Ganze ist dann natürlich in eine for-Schleife eingebunden - wollte euch das drumherum der Übersicht halber aber ersparen.

    Wäre super, wenn mir da jemand weiter helfen könnte!

    Mit freundlichen Grüßen,
    Snirg0r 🙂


  • Mod

    Wenn ungültige Zeichen bei einer Leseaktion eingegeben werden, passiert (unter anderem) folgendes:

    • Die Zeichen verbleiben noch im Eingabestream
    • Das Streamobjekt wird in einen Fehlerzustand versetzt, alle folgenden Aktionen darauf schlagen automatisch fehl, so lange man sich nicht darum kümmert.

    Folglich:

    • Zunächst musst du feststellen, ob und warum der Stream in einen Fehlerzustand übergegangen ist. Du kannst dafür beispielsweise den Rückgabewert deiner Leseaktion prüfen:
    if (cin >> spielfeld[i][k]) 
      // alles ok
    

    Spezifischer willst du wissen, ob cin.fail() wahr ist (oder wenn man es ganz genau nimmt, willst du nur das failbit prüfen, da ios::fail auch auf das badbit prüft, welches aber eine andere Art von Fehler signalisiert), da obiges auch auf eof prüft, was du eventuell anders behandeln willst.

    • Dann muss der Stream aus dem Fehlerzustand geholt werden. Du signalisierst so, dass du den Fehler erkannt hast und dich darum kümmerst. cin.clear() macht dies.
    • Dann müssen die unerwünschten Zeichen aus dem Stream entfernt werden. Das geht mit ignore. Wie viele Zeichen man wie genau entfernt, ist eine eigene Frage. Ich selber ignoriere gerne nur ein einzelnes Zeichen, andere LEute ignorieren gerne bis zum nächsten Zeilenumbruch.

    Insgesamt also:

    if (cin >> spielfeld[i][k])
    {
       // Eingabe war eine Ganzzahl.
       // Hier deine Prüfungen, ob die Eingabe im gültigen Bereich lag
       // und Verarbeitung der Eingabe
    }
    else if (cin.fail())
    {
       // Eingabe war keine Ganzzahl
       // Hier deine Fehlerbehandlung
       // die unter anderem folgendes beinhalten sollte:
       cin.clear();
       cin.ignore(1);  // oder eben mehr
    }
    else
    {
       // Ende der Eingabe (EOF)
       // Hier deine Fehlerbehandlung. Keine Ahnung, wie du darauf reagieren möchtest
    }
    


  • Hi SeppJ!

    Na, das nenne ich ja mal aufschlussreich! Danke Dir dafür. Ich versuche genau das gerade an einer einfacheren Stelle in meinem Programm umzusetzen.

    Mit dem

    if (cin >> spielfeld[i][k])
    

    sage ich ja eigentlich nur: Wenn eine Eingabe, dann mach..., oder?

    Dein Code funktioniert bei mir nur soweit, dass nun Fehleingaben zu keinem Programmabsturz mehr führen. Richtige Eingaben mag er dafür nicht mehr so gerne.

    Ich zeige nun mal, wie ich das bei mir an der anderen Stelle eingebaut habe. Je nachdem, welche Zahl "choice" hat, soll die entsprechende Funktion aufgerufen werden:

    cin >> choice;
        if (cin >> choice){
    	    if (choice == 1){
    	       einlesen(spielfeld, sprache, id);
    	       goto topmenu;
    	    }
    	    if (choice == 2){
    	       lebensregeln(spielfeld);
    	       ausgeben(spielfeld, sprache, id);
    	       goto topmenu;
    	    }
    	    if (choice == 3){
    	       ausgeben(spielfeld, sprache, id);
    	       goto topmenu;
    	    }
    	    if (choice == 4){
    	       meldung (sprache, id = 18); //Meldung 18 Byebye
    	       getch();
    	       exit(0);
    	    }
        } //if cin >> choice
    
        else if (cin.fail()){
        	meldung (sprache, id = 10); //Meldung 10 Falsche Eingabe
        	cin.clear(); 
       		cin.ignore(1);
       		goto topmenu;
        }
    
        else{
        	meldung (sprache, id = 10); //Meldung 10 Falsche Eingabe
        	cin.clear(); 
       		cin.ignore(1);
       		goto topmenu;
        }
    

    Wenn ich eine Ganzzahl eingebe, lädt er bei mir ewig. Und erst wenn ich die Ganzzahl noch einmal eingebe, ruft er die entsprechende Funktion auf.

    Äußerst mysteriös!

    Mir ist klar, dass das nicht gerade optimal ist, eine andere Stelle zu verwenden um zu testen, aber beim Feld ist der Code in meinem Programm noch etwas dichter und unübersichtlicher, deshalb nehme ich lieber diese Stelle. Bitte um Entschuldigung!

    Mit freundlichen Grüßen,
    Snirg0r


  • Mod

    • Lass goto sein! Vorerst nicht nutzen. In ein paar Monaten bis Jahren, wenn du wirklich viel Erfahrung hast, kannst du dir dann überlegen, ob und wo vielleicht mal gelegentlich ein goto angebracht wäre. Aber in Anfängerhänden führt das erfahrungsgemäß unweigerlich zu schlimmstem Spagetticode.

    Mir ist durchaus klar, dass mein Beispielcode irgendwie ein goto provoziert, da ich nur eine einzelne Eingabe ohne Eingabeschleife gezeigt habe und die einfachste Art aus einem if eine Schleife zu machen eben ein goto ist. Ich hatte gehofft, dass du mein Beispiel auf deinen Fall übertragen kannst, anstatt tatsächlich meinen Code zu nehmen und auf Biegen und Brechen in dein Programm ein zu bauen.

    • Deine Zeilen 1 und 2: Ich glaube, du hast das Prinzip nicht verstanden. Der operator>> ist ein ganz normaler Funktionsaufruf. Der hat einen Rückgabewert. Diesen kann man prüfen. Das ist es, was mit dem if(cin >> wert) gemeint ist. Der operator>> wird mit den Argumenten cin und wert aufgerufen* und liefert einen Wert zurück, der dann vom if ausgewertet wird.

    Das bedeutet, du hast hier in Zeile 1 einen Aufruf der Einlesefunktion, deren Rückgabewert verworfen wird (aber choice wird natürlich trotzdem der gelesene Wert zugewiesen. Der Rückgabewert ist nicht der gelesene Wert, sondern eine Referenz auf den Eingabestream selbst) und in der nächsten Zeile noch eine Einlesefunktion, wobei dieses Mal die Rückgabe ausgewertet wird. Dies ist der Grund, wieso du derzeit die Eingabe zwei mal machen musst.

    • Deine Behandlung des eof-Falls ist ein bisschen komisch. Es wurde das Ende der Eingabe erreicht. Es ist keine falsche Eingabe, sondern es ist gar keine Eingabe. D.h., wenn die Quelle der Eingaben eine Datei ist, dann ist das wirklich das Ende der Datei. Wenn die Quelle zum Beispiel eine Tastatur ist, dann hat der Nutzer CTRL+Z/CTRL+D (je nach System) gedrückt und somit der Konsole signalisiert, dass er keine weiteren Eingaben machen wird. Es kommt nichts mehr. Das nächste Zeichen zu löschen bringt da herzlich wenig, es gibt kein nächstes Zeichen und es kann auch kein nächstes Zeichen mehr kommen.

    Diesen Fall kannst du eigentlich nicht sinnvoll in deinem Programm behandeln, daher habe ich auch keinen konkreten Vorschlag gemacht. Die sinnvollste Reaktion ist, das Programm einfach zu beenden.

    Damit, besonders mit dem zweiten Punkt, solltest du deine Probleme lösen können. Zeig am besten deine Lösung. Die C++-Eingabestreams sind nicht wirklich auf Nutzerinteraktion ausgelegt, daher ist das Thema so hakelig und man muss viel tricksen. Die guten Tricks musst du eben nach und nach lernen, indem jemand hier deinen Code verbessert.

    *: Ganz genau genommen ist in diesem Fall der operator>> eine Memberfunktion von istream, meine Beschreibung ist also etwas unpräzise.



  • Deine Zeilen 1 und 2: Ich glaube, du hast das Prinzip nicht verstanden. Der operator>> ist ein ganz normaler Funktionsaufruf. Der hat einen Rückgabewert. Diesen kann man prüfen. Das ist es, was mit dem if(cin >> wert) gemeint ist. Der operator>> wird mit den Argumenten cin und wert aufgerufen* und liefert einen Wert zurück, der dann vom if ausgewertet wird.

    Das bedeutet, du hast hier in Zeile 1 einen Aufruf der Einlesefunktion, deren Rückgabewert verworfen wird (aber choice wird natürlich trotzdem der gelesene Wert zugewiesen. Der Rückgabewert ist nicht der gelesene Wert, sondern eine Referenz auf den Eingabestream selbst) und in der nächsten Zeile noch eine Einlesefunktion, wobei dieses Mal die Rückgabe ausgewertet wird. Dies ist der Grund, wieso du derzeit die Eingabe zwei mal machen musst.

    heißt das es reicht

    if (cin >> choice){....}
    

    zu schreiben und der wert wird eingelesen und bei choice gespeichert? prüft der dann wenn die eingabe eine int-zahl ist dann ist sie wahr?
    Wenn ja wie macht die Funktion dann bei char?
    Mit dem fettgedrucktem meinst du verworfen weil in der nächsten zeile einfach "darüber geschrieben" wird?
    Habe das Problem bei meinen Aufgaben auch immer weil ich davon ausgegangen bin wenn ich prüfe ob die eingabe von z.b. ein int wert von 1-9 ist dann gehe ich beim rest davon aus das es fehlerhaft ist aber so funktioniert das halt nicht 😞



  • Ja, ich weiß, dass Goto im Spaghetticode enden kann, deshalb sind das bei mir auch wenige Ausnahmen wo ich's verwende und nur winzige Schritte (ein paar Zeilen nach oben). Nicht "die feine englische..." =I

    Also, wenn die Abfrage nur ins if packe, dann funktioniert das!

    if (cin >> choice){....}
    

    reicht also.

    Das freut mich! Noch eine Frage - und zwar: wie kann ich ihm klar machen, dass er maximal ein Zeichen akzeptieren darf und nicht bei mehreren Zeichen alle nacheinander abarbeitet?

    Bin gerade etwas in Eile, ich beschäftige mich später näher mit deinen Hinweisen, SeppJ!

    Danke, soweit! 🙂



  • Vermutlich würde man `std::cin.ignore(numeric_limits<streamsize>::max());[c] nach jedem Lesen aufrufen. D.h man liest ein Zeichen und schmeisst den Rest weg.

    Zumindestens, wenn du den Rest, den der User eingegeben hat wirklich nicht akzeptieren und verarbeiten willst.

    Ich weiß aber gerade gar nicht, ob operator>> failtbit setzt, wenn man sozusagen "zuviel" eingibt. Hört sich aber unlogisch. Kanns leider gerade nicht prüfen, weil Javazwang.

    [c]goto` ist für dich auch wenns "nur ein paar Zeilen weiter hoch" springt trotzdem einfach nicht akzeptabel, weil du anscheinend die Alernative schlicht weg nicht kennst.

    Während du C++ lernst solltest du einfach vergessen, dass goto existiert und eine Lösung, die es verwendet, nicht als solche akzeptieren.



  • Man, ich habs echt drauf mit den Tags.


  • Mod

    Mvstylez schrieb:

    heißt das es reicht

    if (cin >> choice){....}
    

    zu schreiben und der wert wird eingelesen und bei choice gespeichert? prüft der dann wenn die eingabe eine int-zahl ist dann ist sie wahr?
    Wenn ja wie macht die Funktion dann bei char?
    Mit dem fettgedrucktem meinst du verworfen weil in der nächsten zeile einfach "darüber geschrieben" wird?
    Habe das Problem bei meinen Aufgaben auch immer weil ich davon ausgegangen bin wenn ich prüfe ob die eingabe von z.b. ein int wert von 1-9 ist dann gehe ich beim rest davon aus das es fehlerhaft ist aber so funktioniert das halt nicht 😞

    Der Rückgabewert der (allermeisten) Lesefunktionen ist der Stream selbst (bzw. eine Referenz darauf, da Streams nicht kopiert werden können). Das heißt cin >> irgendwas gibt cin zurück. Nur deshalb ist es möglich, solche Aktionen aneinander zu hängen:

    cin >> irgendwas >> irgendwas_anderes
    

    Zuerst wird cin >> irgendwas ausgewertet, das gibt cin zurück. Es bleibt also cin >> irgendwas_anderes übrig und das ist wieder ein gültiger Aufruf einer der Lesefunktionen und kann durchgeführt werden. Diese gibt dann wieder cin zurück.
    Aber was bringt das einem, wenn man den Stream selbst als Rückgabewert hat? Nun, man könnte natürlich die Funktionen aufrufen, die testen, ob ein Stream in einem Fehlerzustand ist, zum Beispiel:

    if((cin >> irgendwas).fail()) // ...
    

    Wieder wird zuerst cin >> irgendwas ausgewertet, das gibt wieder cin zurück, auf dem dann die fail -Funktion aufgerufen wird, die zurück gibt, ob der Stream im fail-Zustand ist. Aber die Streams haben noch mehr Funktionen, unter anderem eine automatische Konvertierung in bool'schen Ausdrücken*. Diese ergibt true, wenn kein Fehlerwert gesetzt ist und false, wenn eines der fail-, bad- oder eof-Flags gesetzt ist. Diese Flags werden gesetzt, wenn eine Leseaktion fehl schlägt. fail, weil das was man einlesen wollte nicht zum Format passt, beispielsweise ein Buchstabe wo eine Zahl erwartet wird (Und es ist kein Fehler, wenn noch irgendwas folgt. Wieso sollte das ein Fehler sein? Das ist einfach die nächste Eingabe!). bad, wenn irgendwas total kaputt ist. eof, wenn über das Ende des Streams hinaus gelesen wurde (Und nicht, wie von vielen schlechten Lehrern angenommen, wenn das Ende erreicht ist. Wieso sollte das ein Fehler sein? Es ging doch bis dahin alles gut und wer weiß, was die Zukunft bringt?).
    Somit erhält man auch das Grundkonstrukt der typischen C++-Leseschleife:

    while(eingabestream >> daten)
    {
      verarbeite(daten);
    }
    

    "Lese Daten, so lange es gut geht."

    Sollte eigentlich in jedem guten Buch erklärt sein. Ist übrigens ein einfacher Indikator für die ganz, ganz schlechten Bücher/Lehrer, wenn sie einem stattdessen

    while(!stream.eof())
    {
      stream >> daten;
      verarbeite(daten);
    }
    

    andrehen wollen. Das ist, nach obiger Erklärung, offensichtlich totaler Unsinn+. Wenn man so etwas in einem Buch sieht, dann kann man damit gleich zum Altpapiercontainer gehen.

    *: Genau genommen ist es eine Konvertierung zu void* . Warum das so ist, kann in einem anderen Thread erklärt werden. Es ist eher eine Behelfskrücke mit unerwünschten Nebenwirkungen, da so etwas wie cout << cin kein Fehler ist, sondern einfach einen Pointer ausgibt.

    +: Sicherheitshalber noch eine Erklärung: Der Code ist doppelt falsch. Erstens wird nur auf eof geprüft. Passiert irgendein anderer Fehler, hat man eine Endlosschleife, denn alle Aktionen auf dem Stream schlagen fehl und man kann nie die Schleife verlassen. Zweitens erfolgt die Prüfung erst nachdem die Daten verarbeitet wurden. Das heißt, bei einem Lesefehler verarbeitet man irgendwelche Mülldaten, bevor man den Fehler bemerkt.



  • Starke Ansage. Ich glaub ich habs soweit kapiert. Der untere Stern gilt deinem falschen Code, richtig? Da ich mit

    !stream.eof()
    

    eben nur auf eof-flags prüfe und bad-, fail-flags außer Acht lasse.

    Ich war mal so frei zu beweisen, dass ich mich auch fähig fühle das Programm ohne Goto zum Laufen zu bringen:

    //************Menü************    
        while (sprache == 'd' || sprache == 'e'){
    
    	    meldung (sprache, id = 17); //Meldung 17 Menü
    	    meldung (sprache, id = 13); //Meldung 13 Einlesen
    	    meldung (sprache, id = 14); //Meldung 14 Iteration
    	    meldung (sprache, id = 15); //Meldung 15 Ausgabe
    	    meldung (sprache, id = 16); //Meldung 16 Exit
    	    meldung (sprache, id = 3); //Meldung 3 Eingabe
    
    		if(cin >> choice){ //Wenn Rückgabewert ok, dann...
    
    		    switch (choice){
    			    case 1: einlesen(spielfeld, sprache, id);
    			    		break;
    
    			    case 2: lebensregeln(spielfeld);
    			       		ausgeben(spielfeld, sprache, id);
    			       		break;
    
    			    case 3: ausgeben(spielfeld, sprache, id);
    			    		break;
    
    			    case 4: meldung (sprache, id = 18); //Meldung 18 Byebye
    			    		getch();
    			    		exit(0);
    						break;
    			}
    
    		} //if cin choice
    		else if (cin.fail()){ //Wenn Rückgabewert -> Fail-Flag (Buchstabeneingabe), dann
    		cin.clear();
    		cin.ignore();
    		}
    		else{
    		exit(1);
    		}
    
    	} //while Menü
    

    SeppJ, deine Antworten sind schon der Hammer. Ich lese da zweimal, bis ich dir folgen kann 🙂

    Sehe ich das richtig, dass ich mit dem

    else if (cin.fail())
    

    den Rückgabewert auf fail-flags überprüfe? Das heißt, das ist dann eigentlich meine Überprüfung auf falsche Eingaben (/Formate - in dem Fall Buchstaben oder Sonderzeichen), oder? Nun, da ich meine Eingaben sowieso nur mit der Tastatur mache, kann ich doch fast das

    else if
    

    weg lassen, einfach nur

    else
    

    verwenden und habe damit alle Flags abgedeckt, oder? Ist es notwendig da in meinem Fall noch mal zu unterscheiden?

    Nehmen wir mal an ich würde eine eof-Flag als Rückgabewert bekommen (kann ich aber nicht, oder?), könnte ich dann auch mit cin.clear() und cin.ignore() das Programm vor der Endlosschleife retten und einfach wieder ins Menü zurückkehren?

    @cvcv: Ich habe das mit den Mehrfacheingaben ausprobiert, komme aber noch nicht so richtig klar damit. Muss ich anstelle von streamsize dann was eingeben? Ich probiere weiter.

    Super Forum, einfach klasse!

    Danke!


  • Mod

    Der untere Stern gilt deinem falschen Code, richtig?

    Ja.

    Ich war mal so frei zu beweisen, dass ich mich auch fähig fühle das Programm ohne Goto zum Laufen zu bringen:

    Habe gerade keine Zeit, es anzugucken. Vielleicht jemand anderes. Oder ich, in ein paar Stunden.

    Sehe ich das richtig, dass ich mit dem

    else if (cin.fail())
    

    den Rückgabewert auf fail-flags überprüfe?

    Nicht direkt einen Rückgabewert. Du prüfst hier den Stream cin direkt. Wenn eine vorherige Leseaktion fehlschlug, behält der aber seine Fehlerflags, bis clear benutzt wird.

    Das heißt, das ist dann eigentlich meine Überprüfung auf falsche Eingaben (/Formate - in dem Fall Buchstaben oder Sonderzeichen), oder?

    Jain. Die Überprüfung erfolgte im Prinzip schon in Zeile 11. Da hast du festgestellt, ob alles richtig lief. Hier prüfst du, wenn etwas fehl schlug, warum genau es fehl schlug. Ich wollte verdeutlichen, dass es verschiedene Arten von Fehlern geben kann, die man einzeln prüfen kann. Aber ehrlich gesagt prüfe ich selber meistens nur wie in Zeile 11 ob alles in Ordnung war. Wenn etwas falsch lief, dann lief es eben falsch und es ist relativ egal, was genau der Fehler war. Hier, bei einer Benutzerinteraktion, kann es aber ganz nützlich sein, genauere Meldungen zu geben. Es ist eben schon wichtig, ob der Nutzer etwas falsch eingab oder ob er explizit die Eingabe abgeschlossen hat (siehe nächster Absatz).

    snirg0r schrieb:

    Nehmen wir mal an ich würde eine eof-Flag als Rückgabewert bekommen (kann ich aber nicht, oder?),

    Doch. Unter Windowskonsolen CTRL+Z drücken (muss glaube ich noch mit Enter bestätigt werden), unter anderen Konsolen CTRL+D drücken (wirkt normalerweise sofort). Das schließt sämtlich Eingaben ab.

    könnte ich dann auch mit cin.clear() und cin.ignore() das Programm vor der Endlosschleife retten und einfach wieder ins Menü zurückkehren?

    Nicht wirklich. Mit clear kannst du den Fehlerstatus aufheben. Aber was willst du an der Stelle noch ignorieren? Da kommst nichts mehr. ignore ist auch eine Leseaktion (eben eine ohne Ergebnis), ignore am Dateiende verursacht daher auch bloß wieder ein eof.

    Wenn der stream Hin- und Herspringen unterstützt (seekg, seekp, tellg, tellp), dann kannst du nach einem clear an eine vorherige Stelle springen. Das funktioniert aber nicht bei jeder Art von Stream, sondern nur bei solchen, wo das auch Sinn macht. fstreams zum Beispiel oder stringstreams.


  • Mod

    Der Code sieht in Ordnung aus. Ich würde aber nie mit exit aus einem Programm aussteigen. Das räumt den Stack nicht ab. Da würde ich eher ein return aus der Funktion machen (sofern es Sinn macht) oder zur Not eine Exception schmeißen (wenn ein return nicht in Frage kommt).

    Oder wir ändern einfach ein bisschen den Programmfluss (ungetestet):

    menüausgabe();
    bool exitflag = false;
    while(!exitflag && !(cin >> choice).eof())
    {
      if(cin.fail())
      {
         cin.clear(); cin.ignore(); continue;
      }
      switch (choice)
      {
        // ...
        case 4: exitflag = true; break;
      }
      menüausgabe();
    }
    

    Ja, ein continue ist auch nichts anderes als ein verherrlichtes goto. Aber da der Effekt lokal begrenzt ist, wird es normalerweise toleriert 🙂 .

    Ein exitflag ist auch nicht gerade die tollste Art. Denn die übliche Art, solch ein Flag zu vermeiden, ist tatsächlich ein vorsichtig eingesetztes goto (oder return/throw, wie oben erklärt). Aber wie schon gesagt, solltest du goto vorerst vermeiden und ich wollte mal eine Alternative vormachen und zeigen, dass diese nicht unbedingt umständlich sein braucht.



  • Habe das exit durch return ersetzt, damit auch der Stack abgeräumt wird 🙂

    Okay. Mein Programm funktioniert soweit. Ich bin äußerst froh so kompetent beraten worden zu sein.

    Die eine Frage bleibt noch offen...

    Wie kann ich das mit den mehreren Eingaben beeinflussen? Gebe ich z.B. "kk" ein, so wird zwei mal das Menü aufgerufen, dabei ist nur einmal gewollt. Er arbeitet also jedes "k" nacheinander ab. Ich habe schon versucht stattdessen choice als "ein-elementiges" (eindimensionales) int-Feld zu verwenden, aber da müsste es doch noch eine andere Möglichkeit geben, oder? Die Anweisung von unten kann ich so nicht verwenden, da dann im Menü nach Durchlaufen einer Schleife gar keine Eingaben mehr gemacht werden können. 😕 Habt ihr da noch was passendes für mich im Repertoire?

    Vielen Dank!


  • Mod

    snirg0r schrieb:

    Wie kann ich das mit den mehreren Eingaben beeinflussen? Gebe ich z.B. "kk" ein, so wird zwei mal das Menü aufgerufen, dabei ist nur einmal gewollt.

    Hast du mein Grundgerüst benutzt? Da sollte das eigentlich nicht passieren. Zeig mal Code.


Anmelden zum Antworten