Automatisches Schließen verhindern



  • Konsolenprogramme schließen sich sofort nach Ausführung der letzten Anweisung. Dies ist vollkommen korrekt, für viele Beginner aber ärgerlich, würden Sie doch gerne die Ausgabe ihres neuen Wunderwerks ansehen können.

    Die Lösung des Problems ist grundsätzlich sehr simpel: Wir fügen am Ende des Programms noch eine weitere Anweisung ein, die auf einen Tastendruck des Benutzers wartet.

    Leider tauchen in diesem Zusammenhang zwei Probleme auf:

    • Die Eingabe von Konsolenprogrammen ist gepuffert, so kann es passieren, dass Daten aus dem Puffer als Tastendruck gewertet werden und sich das Programm daraufhin trotzdem sofort schließt
    • Die Standardbibliotheken von ANSI-C und auch ISO-C++ bieten keine Möglichkeit auf einen *beliebigen* Tastendruck zu warten

    Wer auf Punkt 2 verzichten kann (das Programm wartet stattdessen auf das nächste "Enter") ist mit folgender Funktion gut bedient (Punkt 1 wird dadurch gelöst den Puffer zuvor zu leeren):

    // ISO-C++-Version
    #include <iostream>
    using namespace std;
    ...
    void wait ()
    {
        // Löscht etwaige Fehlerzustände die das Einlesen verhindern könnten
        cin.clear();
        // Ignoriert soviele Zeichen im Puffer wie im Puffer vorhanden sind
        // (= ignoriert alle Zeichen die derzeit im Puffer sind)
        cin.ignore(cin.rdbuf()->in_avail());
        // Füge alle eingelesenen Zeichen in den Puffer bis ein Enter gedrückt wird
        // cin.get() liefert dann das erste Zeichen aus dem Puffer zurück, welches wir aber ignorieren (interessiert uns ja nicht)
        cin.get();
    }
    ...
    int main ()
    {
        ...
        wait(); // Warten auf Enter
        return 0;
    }
    

    Wer zu den unglücklichen Personen gehört, bei denen diese Version nicht funktioniert (ist afaik abhängig vom Compiler) hat die Möglichkeit die cin.ignore()-Zeile durch folgende Zeile zuersetzen:

    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    

    Zusätzlich müsst ihr dann aber auch die Includes um folgende Zeile erweitern:

    #include <limits>
    

    Es existiert auch eine C-Version, allerdings hat diese undefiniertes Verhalten (⚠), funktioniert zwar bei fast allen Compilern, dies muss aber nicht so sein!

    // C-Version (nicht ANSI-C weil undefiniertes Verhalten!)
    #include <stdio.h>
    ...
    void wait ()
    {
        // Setzte Puffergröße auf 0 (=> leere Puffer)
        setvbuf(stdin, NULL, _IONBF, 0);
        // Setze Puffergröße wieder auf die ursprüngliche Größe zurück
        setvbuf(stdin, NULL, _IOFBF, BUFSIZ); 
        // Füge alle eingelesenen Zeichen in den Puffer bis ein Enter gedrückt wird
        // getchar() liefert dann das erste Zeichen aus dem Puffer zurück, welches wir aber ignorieren (interessiert uns ja nicht)
        getchar();
    }
    ...
    int main ()
    {
        ...
        wait(); // Warten auf Enter
        return 0;
    }
    

    Um tatsächlich auf einen *beliebigen* Tastendruck zu warten (= Behebung von Punkt 2), müssen wir uns von den Standardbibliotheken der beiden Programmiersprachen wegbewegen. Für die Windows-Konsole bietet die WinAPI die nötigen Hilfsmittel:

    #include <conio.h>
    #include <windows.h>
    ...
    void wait ()
    {
        // Leere Puffer
        FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
        // Lese den nächsten Tastendruck
        getch();
    }
    

    Achtung: Der Aufruf von system("pause") ist kein adäquater Ersatz! Warum system() grundsätzlich gemieden werden sollte (nicht nur weil es verdammt langsam ist), findet ihr in diesem FAQ-Beitrag: http://www.c-plusplus.net/forum/viewtopic-var-t-is-39453.html

    ================================================================================

    Folgende Diskussionen im Forum bzw. externe Quellen haben zu diesem Beitrag geführt:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-263283.html

    PS: Wenn ihr Fehler findet, meldet euch bitte umgehend.


Anmelden zum Antworten