Seltsames vorgehen bei Eingabe von String KLASSEN



  • Plattfuss schrieb:

    Also bei cin >> scheinbar wegen dem '>>' wird der Text nur eingelesen bis zur nächsten Leertaste, weil Magie halt.

    operator>> ließt solange ein, bis er auf ein Whitespace (Leerzeichen, Tab, Enter, usw) stößt, weil genau das der Sinn von >> ist.



  • o90o90o90o schrieb:

    volkard schrieb:

    Der Operator << liest bis zum nächsten White-Space (Zeilenumbruch, Tabulator, Leerzeichen) und macht das sonst auch immer so, bei bool, int, short, float, ..., auch bei string. Alles andere wäre verwirrend.

    Warum? Bei der Ausgabe >> ist es auch nicht verwirrend, dass ein String mit Leerzeichen ausgegeben wird. Ich glaube das aktuelle verhalten von << verwirt mehr Leute.

    Nach der Logik müsste der extraction Operator bei Strings alles bis "EOF" lesen. Da man mit dem insertion Operator auch wunderbar Newlines mit ausgeben kann.
    Das wäre aber reichlich beknackt.



  • hustbaer schrieb:

    o90o90o90o schrieb:

    volkard schrieb:

    Der Operator << liest bis zum nächsten White-Space (Zeilenumbruch, Tabulator, Leerzeichen) und macht das sonst auch immer so, bei bool, int, short, float, ..., auch bei string. Alles andere wäre verwirrend.

    Warum? Bei der Ausgabe >> ist es auch nicht verwirrend, dass ein String mit Leerzeichen ausgegeben wird. Ich glaube das aktuelle verhalten von << verwirt mehr Leute.

    Nach der Logik müsste der extraction Operator bei Strings alles bis "EOF" lesen. Da man mit dem insertion Operator auch wunderbar Newlines mit ausgeben kann.
    Das wäre aber reichlich beknackt.

    o90o90o90o schrieb:

    Ich glaube es gibt keinen der mit einer einfachen Console (nicht Editor) arbeitet und erwartet, dass bei einer String Eingabe nicht genau beim drücken von Enter diese fertig ist, außer, wenn er mit C++ arbeitet.



  • Ich meine nur dein Argument "<< gibt ja auch Whitespaces aus, also sollte >> sie auch mit einlesen" ist etwas komisch.
    Dann dann auch "<< gibt ja auch Newlines aus, also sollte >> sie auch mit einlesen" gelten müsste.

    Du kannst nicht eines dieser beiden Argumente bringen und das andere ablehnen, die Logik beider ist exakt die selbe.

    o90o90o90o schrieb:

    Ich glaube es gibt keinen der mit einer einfachen Console (nicht Editor) arbeitet und erwartet, dass bei einer String Eingabe nicht genau beim drücken von Enter diese fertig ist, außer, wenn er mit C++ arbeitet.

    Das mag wohl sein, hat aber wie gesagt mit deinem "<< gibt auch Whitespaces aus" Argument nichts zu tun.

    Und nicht alles was sich Anfänger im ersten Moment erwarten ist auch die optimale Lösung.

    Die "Whitespace = Stop" Variante hat z.B. den Vorteil dass bei ">>" alle vordefinierten Operator gleich arbeiten, unabhängig vom Datentyp. Für alle gilt "Whitespace = Stop".

    Würde ">>" bei Strings dagegen bis zum Zeilenende lesen wäre diese Symmetrie/Gemeinsamkeit zerstört. Und es gäbe keine andere Symmetrie/Gemeinsamkeit die man dadurch gewinnt. Weil sich ja wie gesagt ">>" mit Strings dadurch immer noch nicht gleich verhält wie "<<" mit Strings.



  • Eigentlich macht "Whitespace = Stop" auf der Console auch bei den anderen Datentypen keinen Sinn. Consoleneingabe endet einfach bei Enter und nicht bei Space. Das Problem dürfte wohl sein, dass man so tut, also ob die Console eine Datei wäre.



  • Und es würde noch weniger Sinn machen es auf der Konsole anders zu handhaben als in Files.
    Überleg dir mal wie verwirrend DAS wäre.

    Aber ich vermute dass es dir gar nicht mehr um die Sache geht, sondern einfach nur darum Recht zu haben.



  • @o90o90o90o: Es ist ja gerade der Sinn, daß sich Tastatureingaben genauso verhalten wie Dateien, damit man einfach in der Konsole die Ein- und Ausgabe umleiten kann, z.B.

    program <input.txt >output.txt 2>error.txt
    


  • o90o90o90o schrieb:

    Eigentlich macht "Whitespace = Stop" auf der Console auch bei den anderen Datentypen keinen Sinn. Consoleneingabe endet einfach bei Enter und nicht bei Space.

    double x, y, z;
    std::cout << "Geben Sie drei Zahlen ein: " << std::flush;
    std::cin >> x >> y >> z;
    

    ...und jetzt versuchen wir das mal, wenn wir nur Zeilen einlesen können. Vor allem, wenn du jetzt nicht völlig Amok laufen und std::istringstream ein anderes Verhalten als std::istream geben willst.

    o90o90o90o schrieb:

    Das Problem dürfte wohl sein, dass man so tut, also ob die Console eine Datei wäre.

    Das wird damit zusammenhängen, dass die Konsole eine Datei ist.

    Das Problem hier besteht allein darin, dass dir nicht klar ist, dass operator>> keine rohe, sondern eine formatierte Einlesefunktion ist -- ein Konzept, das in den meisten Sprachen gleich oder ähnlich existiert. Wenn du eine Zeile haben willst, gibt es std::getline.



  • seldon schrieb:

    double x, y, z;
    std::cout << "Geben Sie drei Zahlen ein: " << std::flush;
    std::cin >> x >> y >> z;
    

    ...und jetzt versuchen wir das mal, wenn wir nur Zeilen einlesen können. Vor allem, wenn du jetzt nicht völlig Amok laufen und std::istringstream ein anderes Verhalten als std::istream geben willst.

    Nein, ich will für consolen Eingabe einen vernünftigen stream der nichts mit std::istream zu tun hat.

    Funktioniert ja sowieso nicht wie ein file stream (siehe seek).

    int main()
    {
    	int x;
    	std::cout << "Verkaufspreis ihres Autos in Euro: " << std::flush;
    	std::cin >> x;
    	if ( !std::cin.fail() )
    		std::cout << "Ihr Auto wurde fuer " << x << " Euro verkauft. Glueckwunsch.\n";
    
    	std::cin.seekg(0, std::cin.beg);
    	int xNochmal = 0;
    	std::cin >> xNochmal;
    	std::cout << "Nochmal x: " << xNochmal;
    }
    

    Verkaufspreis ihres Autos in Euro: 12 000
    Ihr Auto wurde fuer 12 Euro verkauft. Glueckwunsch.
    Nochmal x: 0

    Und vonwegen string und int verwenden die gleichen Trennzeichen. 🙄

    Verkaufspreis ihres Autos in Euro: 123sowasDerVerwendetJaNichtMalEinheitlichSpac
    e...
    Ihr Auto wurde fuer 123 Euro verkauft. Glueckwunsch.
    Nochmal x: 0

    Damit ist volkards Argument ja noch schlechter als gewolftes Zeugs.



  • o90o90o90o schrieb:

    seldon schrieb:

    double x, y, z;
    std::cout << "Geben Sie drei Zahlen ein: " << std::flush;
    std::cin >> x >> y >> z;
    

    ...und jetzt versuchen wir das mal, wenn wir nur Zeilen einlesen können. Vor allem, wenn du jetzt nicht völlig Amok laufen und std::istringstream ein anderes Verhalten als std::istream geben willst.

    Nein, ich will für consolen Eingabe einen vernünftigen stream der nichts mit std::istream zu tun hat.

    Den wirst du nicht kriegen. Für den C++ Standard gibt es so etwas wie Konsolen nicht. cin ist einfach nur irgendein Inputstream (deswegen std::istream = keine genauere Spezifiezierung), der standardmäßig fürs Einlesen verwendet wird.

    Und vonwegen string und int verwenden die gleichen Trennzeichen. 🙄

    Verkaufspreis ihres Autos in Euro: 123sowasDerVerwendetJaNichtMalEinheitlichSpac
    e...
    Ihr Auto wurde fuer 123 Euro verkauft. Glueckwunsch.
    Nochmal x: 0

    Damit ist volkards Argument ja noch schlechter als gewolftes Zeugs.

    Was für eine Zahl sollte er deiner Meinung nach extrahieren?
    Es ist absolut in Ordnung, wenn er bei dem Buchstaben abbricht.



  • Nathan schrieb:

    Und vonwegen string und int verwenden die gleichen Trennzeichen. 🙄

    Verkaufspreis ihres Autos in Euro: 123sowasDerVerwendetJaNichtMalEinheitlichSpac
    e...
    Ihr Auto wurde fuer 123 Euro verkauft. Glueckwunsch.
    Nochmal x: 0

    Damit ist volkards Argument ja noch schlechter als gewolftes Zeugs.

    Was für eine Zahl sollte er deiner Meinung nach extrahieren?
    Es ist absolut in Ordnung, wenn er bei dem Buchstaben abbricht.

    Keine Zahl. Das fail bit muss gesetzt sein.
    Volkards Aussage war:

    volkard schrieb:

    Der Operator << liest bis zum nächsten White-Space (Zeilenumbruch, Tabulator, Leerzeichen) und macht das sonst auch immer so, bei bool, int, short, float, ..., auch bei string.

    Damit ist sein ganzes Argument, dass es sich bei int, float ... string gleich verhält sinnlos. Dann müsste er bei string ja auch schon beim ersten Buchstaben abbrechen, wenn es so sein sollte wie bei int.



  • @o90o90o90o
    Bist du dumm oder sowas?



  • Nicht so dumm wie du.
    Erklär doch mal diese Ausgabe mit dem angeblich einheitlichen Whitespace Separator.

    int main()
    {
    	int x;
    	std::cout << "Verkaufspreis ihres Autos in Euro: " << std::flush;
    	std::cin >> x;
    	if ( !std::cin.fail() )
    		std::cout << "Ihr Auto wurde fuer " << x << " Euro verkauft. Glueckwunsch.\n";
    
    	std::string str;
    	std::cin >> str;
    	std::cout << "string: " << str << "\n";
    
    	int y = 0;
    	std::cin >> y;
    	std::cout << "y: " << y << "\n";;
    
    }
    

    Verkaufspreis ihres Autos in Euro: 123katzekatze678 99
    Ihr Auto wurde fuer 123 Euro verkauft. Glueckwunsch.
    string: katzekatze678
    y: 99



  • o90o90o90o schrieb:

    Nicht so dumm wie du.
    Erklär doch mal diese Ausgabe mit dem angeblich einheitlichen Whitespace Separator.

    Da gibts nichts zu erklären, weil das genau dem Konzept des einheitlichen Whitespace Seperator entspricht.
    Wie hättest du sie den gerne?
    ---
    Wieso diskutier ich überhaupt mit einem, der cout flusht bevor er einliest?



  • o90o90o90o schrieb:

    Nicht so dumm wie du.
    Erklär doch mal diese Ausgabe mit dem angeblich einheitlichen Whitespace Separator.

    int main()
    {
    	int x;
    	std::cout << "Verkaufspreis ihres Autos in Euro: " << std::flush;
    	std::cin >> x;
    	if ( !std::cin.fail() )
    		std::cout << "Ihr Auto wurde fuer " << x << " Euro verkauft. Glueckwunsch.\n";
    		
    
    	std::string str;
    	std::cin >> str;
    	std::cout << "string: " << str << "\n";
    	
    	int y = 0;
    	std::cin >> y;
    	std::cout << "y: " << y << "\n";;
    
    }
    

    Verkaufspreis ihres Autos in Euro: 123katzekatze678 99
    Ihr Auto wurde fuer 123 Euro verkauft. Glueckwunsch.
    string: katzekatze678
    y: 99

    Was habt ihr für Probleme hier 😃

    1. Du willst einen int und du gibst ein 123katzekatze678 99<Enter> . Der extraction operator findet 1 , er findet 2 , er findet 3 . Supi er hat schon drei int gefunden, die er zusammensetzen kann. Nun findet er ein k , shit das ist kein int , also Fehler.
    Ergebnis: Ein int 123 und katzekatze678 99<Enter> bleibt im Puffer liegen.

    2. Du willst einen string lesen. Ein string besteht aus Zeichen. Also kannst du keine falschen Zeichen eingeben (keinen Fehler produzieren), also kann nur ein Whitespace den Einlesevorgang beenden. Der extraction operator findet also Zeichen für Zeichen. Nach dem letzen Zeichen 8 kommt ein Leerzeichen (=Whitespace). Also der Einlesevorgang ist beendet.
    Ergebis. Einen string katzekatze678 und <Leerzeichen>99<Enter> bleibt im Puffer zurück.

    3. Du willst einen int einlesen. Der extraction operator ist clever und überließt (lesen + verwerfen) Whitespaces, die am Anfang stehen (führende Whitespaces). Somit gibt es im Puffer nun nur noch 99<Enter> . Die 99 wird gelesen, das Enter bricht den Einlesevorgang ab.
    Ergebnis: Ein int 99 und der Puffer ist nun leer!



  • Hört doch einfach auf, den Troll zu füttern.
    Und wenn doch, dann wenigstens artgerecht:

    <(((((°>



  • out schrieb:

    3. Du willst einen int einlesen. Der extraction operator ist clever und überließt (lesen + verwerfen) Whitespaces, die am Anfang stehen (führende Whitespaces). Somit gibt es im Puffer nun nur noch 99<Enter> . Die 99 wird gelesen, das Enter bricht den Einlesevorgang ab.
    Ergebnis: Ein int 99 und der Puffer ist nun leer!

    😡 Ups einen Fehler gemacht. Der Puffer ist nicht leer. Das doofe Enter steht noch drin. Nun kannst du z.B. cin.ignore(1) machen, damit der Puffer leer wird.



  • Nathan schrieb:

    o90o90o90o schrieb:

    Nicht so dumm wie du.
    Erklär doch mal diese Ausgabe mit dem angeblich einheitlichen Whitespace Separator.

    Da gibts nichts zu erklären, weil das genau dem Konzept des einheitlichen Whitespace Seperator entspricht.

    So, k ist also ein Whitespace 🙄

    Wieso diskutier ich überhaupt mit einem, der cout flusht bevor er einliest?

    Hab den Code von seldon kopiert.



  • Beantworte meine Frage: Was erwartest du?



  • "Formatierte Eingabe" heißt nicht zwingend, dass an Whitespaces abgebrochen wird.

    Also, mal ganz von vorne, damit es verständlich ist: Eine formatierte Eingabefunktion ist datentypabhängig, nicht streamabhängig (streng genommen bei den Basistypen streitbar, aber das sind Implementationsdetails). Das Verhalten von cin >> str; (wenn std::string str) definiert nicht das Modul basic_istream, sondern das Modul basic_string. Wenn du einen std::complex<double> einliest, definiert auch dessen operator>> und nicht der Stream, was konsumiert wird (und dabei werden auch Whitespaces konsumiert).

    Der Vorteil dieser Herangehensweise ist: Es ist egal, aus was für einem Stream du Strings, komplexe Zahlen oder Objekte deines eigenen Datentypens einlesen willst, du musst nur einen operator>> schreiben und kannst fortan aus std::istringstream, std::ifstream und allem anderen, was std::istream erbt, einlesen (Stichwort Liskov-Substitutierbarkeit).

    Die formatierte Eingabefunktion von std::string definiert sich, und das ist auch in anderen Sprachen durchaus üblich, auf Basis von Tokens, nicht Zeilen -- und erst hier kommt der Abbruch bei Whitespaces ins Spiel. Wenn man die Abstraktion kennt (was man sollte) und das ganze als "ich hab einen Datenstrom, jetzt hol ich mir den nächsten String daraus" liest (was man sollte), ist es auch das, was man intuitiv erwartet. Hier eine Sonderlösung für CLIs hinzuklatschen, das wäre aus meiner Sicht wenig sinnvoll.

    Zum Thema Dateien: Eine Datei ist im Standard definiert als "A File provides an external source/sink stream whose underlaid character type is char (byte)." stdin und stdout fallen darunter, seek hat nichts damit zu tun (und ist hauptsächlich auf der Untermenge sog. "regulärer Dateien" von Belang). Aber bevor wir hier in Wortspiele verfallen: Der relevante Punkt ist, dass man für den Großteil aller Operationen die Konsole genauso behandeln können will wie eine reguläre Datei, eine FIFO oder ein Netzwerksocket, denn dann muss man seinen Code nicht doppelt und dreifach schreiben.

    Zum Thema Flush: std::flush sollte in diesem Zusammenhang nicht notwendig sein, weil std::cout an std::cin getied ist und ein Einlesen aus std::cin dazu führt, dass std::cout automatisch geflusht wird (falls notwendig, wenn die Implementation schlau ist), aber mir sind schon (alte) Implementationen untergekommen, die das nicht so genau nehmen. Wobei die inzwischen nicht mehr relevant sein dürften, so dass ich mir das vielleicht mal abgewöhnen sollte. Tut aber nicht wirklich weh.


Anmelden zum Antworten