Programmbeispiel aus C++-Buch



  • Hallo,
    es wird mir schon richtig peinlich. Ich kann eigentlich schon ganz passabel
    C++, aber dieses eine Beispiel aus meinem C++-Buch kann ich einfach nicht
    verstehen:

    #include <iostream>
    using namespace std;
    
    int main(void) {
       int wert;
       while ( (wert = cin.get()) != EOF ) {
          cout << (char)wert;
       }
       return 0;
    }
    

    Warum werden alle Zeichen erst ausgegeben, wenn die Enter-Taste gedrueckt worden
    ist? Ich meine, es wird ein Zeichen eingelesen, überprüft ob es EOF ist und
    dann ausgegeben, oder???

    Vielen Dank im Voraus!!!



  • Ja schon, aber soweit ich weiß stehen die Zeichen erst in dem cin-Buffer, wenn du auf der Tastatur ENTER drückst.



  • Und was ist dann mit:

    cout<< (char)wert;
    

    Das ist doch eigentlich nur ein Zeichen!!!



  • Änder mal

    cout << (char)wert;
    

    zu

    cout << (char)wert << std::flush;
    

    Dann wird der Ausgabepuffer jedes mal geleert.



  • Ein int wird als Zahlenwert ausgegeben, ein char wird mit ASCII-Tabelle in ein Zeichen umgerechnet - und da deine Variable den Typ int hast, mußt du sie von Hand in einen char umwandeln (das nennt sich "Cast", falls du mehr wissen willst).



  • Danke CStoll. aber das ist nicht die Frage!

    Was ich immer noch nicht ganz verstehe. Warum werden alle Zeichen ausgegeben,
    obwohl nur der wert als char ausgegeben werden dürfte?



  • D schrieb:

    Danke CStoll. aber das ist nicht die Frage!

    Was ich immer noch nicht ganz verstehe. Warum werden alle Zeichen ausgegeben,
    obwohl nur der wert als char ausgegeben werden dürfte?

    Das liegt an der while-Schleife, die dafür sorgt dass jedes Zeichen, das im cin-Buffer steht auch ausgegeben wird. Was du hier machst ist eine Zeichenweise-Ausgabe.



  • Versteht mich den niemand? Eignetlich müsste das ganze doch so laufen:

    Das Programm liest ein Zeichen ein.
    Es gibt das Zeichen aus (cout).

    Warum wird der ganze Puffer erst am Schluss ausgegeben, wenn doch nach jedem Zeicheneinlesen doch das cout kommt??? 😕



  • Weil es eben performanter ist, einmal einen großen Batzen raus zu schreiben anstatt n mal ein einzelnes Zeichen.

    Deswegen hat cout einen *internen* Puffer, und cout entscheidet selber wann es rausgeschrieben wird. Manuell kannst du das per std::cout << std::flush() tun.

    Wenn du einen ungepufferten Stream nutzen willst, nutz std::clog.



  • Das liegt daran, daß zwischen der Tastatur und cin noch der Tastaturpuffer liegt - und der wartet solange, bis du auf ENTER drückst, um dann alle zwischenzeitlich eingegebenen Zeichen im Block an cin zu schicken (und cin ist so geduldig zu warten, bis der Tastaturpuffer tatsächlich etwas sendet).



  • Aber (char)wert ist doch nur ein einziges Zeichen!!!



  • Ja - aber der wird in einer Schleife immer wieder neu gefüllt und ausgegeben 😉

    Nochmal langsam der Ablauf:

    • die Tastatur liest eine komplette Zeile (bis zum NewLine) ein und schickt sie ans Programm
    • in der Schleife holt sich cin nacheinander jedes eingegebene Zeichen, dieses wird in 'wert' gepackt und anschließend ausgegeben
      (beim ersten Schleifendurchlauf wartet cin noch darauf, daß etwas von der Tastatur kommt, anschließend arbeitet es stückweise den Datenhaufen ab, den es von der Tastatur bekommen hat)


  • Also werden die couts im Grunde beim Einlesen übersprungen und erst beim Enter
    dann der Reihe nach ausgegeben:

    #include <iostream>
    using namespace std;
    
    int main() {
       int wert;
    
       wert = cin.get();
       cout<<char(wert);
    
       // zum Test
       cout<<"\nHallo\n";
    
       wert = cin.get();
       cout<<char(wert);
    
       return 0;
    }
    

    In dem Beispiel werden also zuerst zwei Zeichen eingelesen (und damit das erste
    cout und den Test übersprungen und danach erst alles ausgegeben (mit Hallo!).

    Wenn man drei Zeichen eingibt werden trotzdem nur die ersten zwei ausgegeben.
    Habe ich das jetzt richtig verstanden???

    Jetzt noch eine Frage. Was ist der Unterschied zwischen cin.get(blabla); und
    blabla = cin.get();? Beim ersten wird ein char gefordert und beim zweiten ein
    int, aber gibt es sonst einen Unterschied???



  • Nicht ganz - erst werden die zwei Zeichen eingegeben und dann läuft das Programm durch, holt sich nacheinander die Eingaben und schreibt sie raus (btw, das NewLine zählt hier auch als Zeichen ;))

    Wenn du mehr Zeichen eingegeben hast als gebraucht werden, bleibt der Rest im Programm stehen und gammelt vor sich hin 😉

    D schrieb:

    Jetzt noch eine Frage. Was ist der Unterschied zwischen cin.get(blabla); und
    blabla = cin.get();? Beim ersten wird ein char gefordert und beim zweiten ein
    int, aber gibt es sonst einen Unterschied???

    technisch machen beide das selbe, ist nur eine Frage der Gewohnheit. Die erste Variante schreibt direkt in ein char und gibt den Stream zurück (damit kann man z.B. mehrere Eingabe-Operationen verketten), die zweite liefert einen int zurück (der entweder ein gültiger char-Wert oder EOF sein kann).



  • Danke. Vielen Dank für die Antworten. Aber mal im Ernst, das ist doch eigentlich
    nicht gerade ein Beispiel für Kapitel 1 eines C++-Buches!!!



  • Die Ein- und Ausgabe würde ich schon recht weit an den Anfang setzen (damit der Neuling auch etwas sehen kann, wenn er sich durch die weiteren Beispiele arbeitet). Daß du dabei gleich über die Interna der IOStream-Library gestolpert bist, war da vermutlich nicht beabsichtigt 😃



  • Was mich vielmehr ärgert, ist dass die in einem C++-Buch einen C-Style-Cast in einem Beispiel anbringen ^^ Den kann man erwähnen, wenn man gerade casts durchgeht. Aber nicht so nen Murks direkt am Start bringen, damit sich der Anfänger das einprägt.



  • The-Kenny schrieb:

    Weil es eben performanter ist, einmal einen großen Batzen raus zu schreiben anstatt n mal ein einzelnes Zeichen.

    Deswegen hat cout einen *internen* Puffer, und cout entscheidet selber wann es rausgeschrieben wird. Manuell kannst du das per std::cout << std::flush() tun.

    Wenn du einen ungepufferten Stream nutzen willst, nutz std::clog.

    da übersiehst du aber, dass cin mit cout verbunden (tie) ist. vor jeder eingabe über cin wird cout geflusht (genauso wird vor jeder ausgabe auf clog oder cerr cout geflusht). das ist also gar nicht das problem hier. das problem ist, dass get auf das erste newline wartet (enter), das eingegeben wird, und dann die ganze zeichenkettenwurst auf einmal in den _eingabe_puffer lädt. cout << flush hat keinerlei auswirkung hier. flush und endl kann man im prinzip die meiste zeit sogar vergessen.

    /edit
    ps: clog ist gepuffert.

    cin ... standardeingabestream
    cout ... standardausgabestream (gepuffert)
    clog ... standardfehlerausgabestream (gepuffert)
    cerr ... standardfehlerausgabestream (ungepuffert)

    auf cerr/clog zu schreiben empfiehlt sich hier also nicht, weil nicht dieselbe ausgabe verwendet wird wie bei cout.



  • Wobei get nicht wirklich wartet, get ruft irgendeine Routine des Betriebssystems auf, die dann wartet, wenn nichts bereit steht.

    D schrieb:

    Aber mal im Ernst, das ist doch eigentlich
    nicht gerade ein Beispiel für Kapitel 1 eines C++-Buches!!!

    Stroustrup, oder? Der hat jedenfalls sowas relativ am Anfang. Das ist eben kein Buch für Programmierneulinge, er geht davon aus, dass man von den wesentlichen Sachen wie Standardein/ausgabe schonmal was gehört hat.


Anmelden zum Antworten