Cin-Buffer



  • Hey ihr,

    Ich habe jetzt schon öfters gehört, dass die CIN-Operation über einen Eingabebuffer verfügt.
    Das bedeutet, dass cin im folgenden Beispiel nicht nur die folgende Variable setzt:

    int c;
    cin >> c;
    

    Sondern mit dem Objekt, der Funktion, der Klasse??? 'Cin' auch noch was passiert.
    Die Daten werden in einen 'Buffer' geladen.

    Dummerweise steht in meinem Buch nichts über diesen Buffer und was genau Cin ist auch nicht.

    Kann mich jemand über diesen Sachverhalt aufklären?
    Es ist nämlich oft so, dass Quelltexte nicht so funktionieren, wie ich es mir vorstelle und das vermutlich einfach an mangelndem Verständnis der Cin-Funktion liegt.

    Wäre nett, wenn mir das jemand erklären könnte.

    cya
    David



  • Ein Stream hat im Hintergrund einfach einen Stream-Buffer, an den er die Ein/Ausgabe-Anweisungen weiterleitet - dieser widerum greift (mehr oder weniger direkt) auf die Hardware zu, um einzelne Zeichen zu bekommen. Bei cin steckt hinter diesem Puffer noch die Tastatursteuerung des Betriebssystems.

    Das bedeutet, "cin>>i;" holt sich solange einzelne Zeichen aus seinem Buffer, wie es ankommenden Zeichen als Ziffer interpretieren kann und baut sich damit den Wert zusammen, der in i gespeichert wird. Der Buffer fordert diese Zeichen dann von der Tastatur ab - und die speichert zunächst alles was du eingibst, in ihrem eigenen Tastaturpuffer und schickt es geschlossen an den cin-Buffer, wenn du Enter drückst.



  • Das klingt alles logisch... Grund zur Frage hatte ich daher, weil ich mit dem im Forum schon so oft diskutierten Problem, dass das Konsolenfenster automatisch schließt meine Probleme hatte.
    Das einzige, was in meinem folgenden Kryptographieprogramm funktioniert ist der so verpönte system("Pause")-Befehl, welchen ich nicht benutzen will.
    Alle Flags sind auf einem Gültigen status.

    Die von Sidewinder empfolene Wait-Funktion erfüllt leider im folgenden Programm ihren Zweck nicht:

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <math.h>
    #include <string>
    #include <windows.h>
    using namespace std;
    void setze_consolenfarbe(int,int);
    void wait(void);
    string verschluessele(string,string);
    int main(void)
    {
       char wort[256];
       string keyone="";
       cout << "Bitte geben Sie eine Nachricht ein, welche verschluesselt werden soll:\n" << endl;
       cout << "Max. 256 Zeichen\n";
       cin.getline(wort,256);
       cout << "\nBitte geben Sie nun den Schluessel an,\nnach dem ihre Nachricht kryptographisch behandelt werden soll.\nBitte beachten Sie, dass von der Schluessellaenge \nauch die Sicherheit abhaengt." << endl;
       cin >> keyone;
       cout << "\n\n\nDIE VERSCHLUESSELTE NACHRICHT, WELCHE VON IHNEN EINGEGEBEN WURDE LAUTET:\n\n" << endl;
       cout << verschluessele(wort,keyone) << endl;
       cout << "\nSollte die Nachricht kuerzer sein als der von ihnen eingegebene Text\nlesen Sie bitte den folgenden Fehlerbericht:" << endl;
       //Fehlererkennung und Auswertung:
       cout << "Fehlerbericht:\n" << endl;
       cout << "Statusflag 'Good':" << cin.good()<<"\n";
       cout << "Statusflag 'Fail':"<<cin.fail()<<"\n";
       cout << "Statusflag 'Bad':"<<cin.bad()<<"\n";      
       if(cin.good() == true)
          cout << "\n\nAuswertung der Flags: \nDas Programm wurde fehlerfrei ausgefuehrt!" << endl;
       else
       {
          cout << "\nAuswertung der Flags:\n" << endl;
          if(cin.fail() == true)
             cout << "\nWie es aussieht wurde eine Fehlerhafte Eingabe gemacht." << endl;
          if(cin.bad() == true)
             cout << "\nEin schwerwiegender Fehler ist aufgetreten!\nBitte ueberpruefen Sie ob eventuell ein zu hoher Eingabewert,\nden Streambuffer zum ueberlaufen gebracht hat." << endl;    
       }       
       //Beenden des Programmes:
       cout << "Einfach noch ne bloede beliebige Taste zum Beenden druecken..." << endl;
       wait();
       system("Pause");   //Sollte eigentlich ja überflüssig sein.
    }    
    string verschluessele(string s, string one)
    {
        int c=0;
        int l = one.length();
        int s_counter=0;
        while(c < s.length())
        {        
           s[c]+= one[s_counter];  
           c++;       
           s_counter++;
           if(s_counter>l)
              s_counter=0;
        }        
        return(s);
    }    
    void wait() 
    { 
        cin.clear(); 
        cin.ignore(cin.rdbuf()->in_avail()); 
        cin.get(); 
    }
    

    Der User gibt eine Nachricht ein, dann einen Schlüssel und es wird für jeden ASCII-Wert in der Nachricht je um den Wert der Stelle im Schlüssel inkrementiert (ROT-n Verfahren)

    Am Ende gebe ich alle Statusflags von CIN aus, welche alle auf 'okay ich funktioniere' stehen.

    Die Waitfunktion beendet das Programm jedoch direkt.

    cya

    David



  • Das Problem bei dieser wait()-Methode ist, daß in_avial() nicht unbedingt die Zeichenzahl im (externen) Tastaturpuffer liefert, sondern die Zeichenzahl im (internen) Buffer von cin. Und auf einigen Systemen ist die permanent 0. Auf der sicheren Seite bist du mit einer modifizierten wait()-Funktion:

    void wait() 
    { 
        cin.clear(); 
        cin.ignore(numeric_limits<streamsize>::max(),'\n'); 
        cin.get(); 
    }
    

    (sollte mal jemand in der Konsolen-FAQ berichtigen)



  • 777 schrieb:

    Die von Sidewinder empfolene Wait-Funktion erfüllt leider im folgenden Programm ihren Zweck nicht:

    Diese sollte folgendermaßen aussehen, weil in_avail nicht immer das gewünschte tut.

    void wait() 
    { 
        cin.clear(); 
        cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
        cin.get(); 
    }
    

    (Achtung Textbaustein *wiederhol*)
    Vielleicht sollte man das in der FAQ mal korrigieren.

    @CStoll: 😃



  • Wäre echt super, wenn das im FAQ geänder wurde.
    Hab keinen Thread gefunden, wo auf das Problem hingewiesen wurde.

    Was muss ich mir unter internem und externem Buffer verstehn?
    Gibts da irgendwo ne Erklärung oder was genau ist das?

    cya
    David



  • Damit habe ich mich auf meine Erklärung oben bezogen - "interner Puffer" ist der Puffer von cin (den kannst du über rdbuf() erreichen), "externer Puffer" ist der Tastaturpuffer des Systems (an den kommst du aus dem Programm heraus nicht dran).

    PS: Ich hab' die Bitt an SideWinder weitergeleitet.



  • Sonst so richtig verstanden?
    Hab mal ne Kleine Paintskizze gemacht 😉

    http://www.postpla.net/attachment.php?attachmentid=4066&stc=1&d=1195209608



  • Keine Ahnung - ich kann die Skizze leider nicht betrachten (da kommt nur eine Fehlermeldung "Ungültige Angabe: Anhang").



  • mhh.. son mist^^
    Ich muss das heute Abend hochladen, wenn ich von der Arbeit zurück bin und auch auf FTP zugreifen kann.
    Momentan lässt das leider der Proxy nicht zu 😞



  • Okay... das hier müsste eigentlich gehen.
    So stelle ich mir cin jetzt vor- nicht als Funktion.
    Sondern als Klasse, mit der Schreibfunktion.

    http://jesusfreak777.je.funpic.de/cin.JPG

    Richtig so?



  • Fast richtig.

    cin.ignore() wirft auch Daten weg, die aktuell noch gar nicht im cin-Puffer stehen. Und die Statusbits liegen nicht im Puffer, sondern im Stream (btw, es gibt auch noch das eofbit - und goodbit ist nur eine Kurzform für "alle Fehlerbits sind zurückgesetzt).



  • Okay... vielen Dank 😉
    Ich denk das reicht dann vorläufig als Erklärung x.DD



  • CStoll schrieb:

    void wait() 
    { 
        cin.clear(); 
        cin.ignore(numeric_limits<streamsize>::max(),'\n'); 
        cin.get(); 
    }
    

    (sollte mal jemand in der Konsolen-FAQ berichtigen)

    Da ich jetzt grade mal bei einem kleinen Testprogramm auf der Konsolen mal diese wait Variante mal ausprobiert habe, bin ich gegenüber der FAQ-Variante auf ein unschönes Verhalten gestolpert:

    FAQ-Variante: Ein Return zum Beenden
    Diese Variante: Zwei Returns sind zum Beenden nötig

    #include <iostream>
    #include <limits>
    
    void wait(bool faqVariante)
    {
    	if(faqVariante)
    	{
    		// FAQ-Variante
    		std::cin.clear();
    		std::cin.ignore(std::cin.rdbuf()->in_avail());
    		std::cin.get();
    	}
    	else
    	{
    		// Neue Variante
    		std::cin.clear();
    		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    		std::cin.get();
    	}
    }
    
    int main()
    {
    	wait(false /* true */);
    	return 0;
    }
    

    Es mag vielleicht an meiner Entwicklungsumgebung liegen (Visual Studio 2005 Std, Windows Vista), sollte aber bevor jemand an der FAQ rumschraubt mal von anderen überprüft werden.

    cu André



  • Hmm, das könnte daran liegen, daß du vor dem wait()-Aufruf keine anderen Eingaben erwartet hast.

    ignore() sucht nach dem ersten \n im Eingabepuffer und entsorgt alle Daten, die davor angekommen sind (und normalerweise hat es die Aufgabe, die Überreste der letzten Eingabe (cin>>irgendwas lässt nachfolgende Whitespaces inklusive des Bestätigungs-ENTER im Tastaturpuffer zurück) zu entsorgen). Das heißt, hier entsorgst du das erste ENTER und wartest dann darauf, daß noch eine Eingabe kommt.

    (mir fällt allerdings keine Möglichkeit ein, portabel festzustellen, ob sich aktuell noch Eingabe-Reste im Tastaturpuffer befinden)



  • ich häng mal eine ähnliche frage an

    char[] string = "Test";
    cin >> string;
    cout << string;
    

    das cout gibt den eingelesenen string aus. ist vielleicht ne naive frage, aber mir fällt erst jetzt auf, dass das funktioniert.

    es geht hier um ein beispiel, dass von einem Cpp-Anfänger kam, ich selbst 😉 würde da sowieso ein paar consts reinhauen.

    gibt cin dabei einen pointer auf ein dynamisches char-feld an? anders könnte ich mir das nicht erklären, sonst wäre ja die alloziierung für den neuen string nicht möglich



  • Nein, cin schreibt einfach in den Speicherbereich, den du ihm zur Verfügung stellst. In dem Fall solltest du aber maximal 4 Zeichen eingeben, sonst zerstörst du im Nebeneffekt die Daten, die hinter dem Array untergebracht sind.

    (PS: Und das nächste Mal verwende bitte einen neuen Thread für eine neue Frage)



  • crashterpiece schrieb:

    ...aber mir fällt erst jetzt auf, dass das funktioniert....

    Ist aber (mehr oder weniger) Zufall.

    crashterpiece schrieb:

    ...ich selbst 😉 würde da sowieso ein paar consts reinhauen...

    Ich würde an Deiner Stelle da erstmal "std::strings reinhauen".

    crashterpiece schrieb:

    ...wäre ja die alloziierung für den neuen string nicht möglich

    Findet ja auch nicht statt.

    😉 😃

    Gruß,

    Simon2.


Anmelden zum Antworten