Seltsames vorgehen bei Eingabe von String KLASSEN
-
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: 0Und 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: 0Damit 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: 0Damit 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: 0Damit 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: 99Was habt ihr für Probleme hier

1. Du willst einen
intund du gibst ein123katzekatze678 99<Enter>. Derextraction operatorfindet1, er findet2, er findet3. Supi er hat schon dreiintgefunden, die er zusammensetzen kann. Nun findet er eink, shit das ist keinint, also Fehler.
Ergebnis: Einint 123undkatzekatze678 99<Enter>bleibt im Puffer liegen.2. Du willst einen
stringlesen. Ein string besteht aus Zeichen. Also kannst du keine falschen Zeichen eingeben (keinen Fehler produzieren), also kann nur ein Whitespace den Einlesevorgang beenden. Derextraction operatorfindet also Zeichen für Zeichen. Nach dem letzen Zeichen8kommt ein Leerzeichen (=Whitespace). Also der Einlesevorgang ist beendet.
Ergebis. Einenstring katzekatze678und<Leerzeichen>99<Enter>bleibt im Puffer zurück.3. Du willst einen
inteinlesen. Derextraction operatorist clever und überließt (lesen + verwerfen) Whitespaces, die am Anfang stehen (führende Whitespaces). Somit gibt es im Puffer nun nur noch99<Enter>. Die99wird gelesen, dasEnterbricht den Einlesevorgang ab.
Ergebnis: Einint 99und 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
inteinlesen. Derextraction operatorist clever und überließt (lesen + verwerfen) Whitespaces, die am Anfang stehen (führende Whitespaces). Somit gibt es im Puffer nun nur noch99<Enter>. Die99wird gelesen, dasEnterbricht den Einlesevorgang ab.
Ergebnis: Einint 99undder Puffer ist nun leer!
Ups einen Fehler gemacht. Der Puffer ist nicht leer. Das doofe Entersteht 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.
-
seldon schrieb:
Das Verhalten von cin >> str; (wenn std::string str) definiert nicht das Modul basic_istream, sondern das Modul basic_string.
[...]
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.Ja, wenn man es oberflächlich betrachtet, stimmt das so.
Genau genommen kommuniziert das Modul basic_string (wie auch für andere Module empfohlen) mit basic_istream (bzw. dessen locale) um das gewünschte Verhalten zu zeigen. basic_string fragt zum Beispiel bei jedem operator>> an, was denn diesesmal als Whitespace gelten sollte und was nicht. Andere Klassen haben sogar deutlich mehr Interaktion mit den facetten von basic_istream, so könnte man zum Beispiel mit einem kleinen Handgriff ändern, dass alle Zahlen im römischen Zahlenformat gelesen werden, was dann auch std::complex betrifft.
-
Wenn man ganz pedantisch sein will, spricht basic_string mit locale, um herauszufinden, ob etwas ein Whitespace ist. std::complex bedient sich bei seinem Werttypen -- etwa wird std::complex<mpf_class> in der gmp nach einem operator>> suchen. (ich hab grad nachgekuckt, die haben keinen operator>> in der gmplib. Verdammt. Also, wenn sie einen hätten, dann würde std::complexs operator>> den in diesem Fall benutzen)
Letztendlich sind solche Details für den groben Überblick aber nicht entscheidend. Wenn ich einen eigenen Datentyp baue und einen operator>> bereitstelle, wird der in der Regel den operator>> anderer Typen für Objektteile verwenden. Nichtsdestoweniger gehört dieser operator>> organisatorisch zu meinem Datentypen; es wäre albern, ihn dem Stream oder den Klassen von Memberobjekten zuzuschlagen. Worauf ich damit hinauswill, ist, dass jeder Typ selbst definiert, wie er formatiert eingelesen werden kann, und dass das nicht zentralisiert beim Stream gemacht werden kann/sollte.
-
Nathan schrieb:
Beantworte meine Frage: Was erwartest du?
Das "123katzekatze678" kein int ist.

seldon schrieb:
"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.
Warum sollte es dann intuitiv sein, dass Space ein string Separator ist, wenn du schon sagst, dass man den Operator beliebig für jeden Datentyp schreiben kann? Warum sollte "123katzekatze678" dann ein int und ein string sein? Da sind garkeine Whitespaces drin.
-
ich muss mich anschließen:
Das Verhalten von op>> ist nicht intuitiv. Entweder "123katzekatze678" zerfällt in int-string-int oder ist eine fehlerhafte Eingabe. Wenn white space eine bedeutung hat, dann als "123 katzekatze 678".
-
otze schrieb:
ich muss mich anschließen:
Das Verhalten von op>> ist nicht intuitiv. Entweder "123katzekatze678" zerfällt in int-string-int oder ist eine fehlerhafte Eingabe. Wenn white space eine bedeutung hat, dann als "123 katzekatze 678".
Ne, ein int-string-int wäre absolut bescheuert. Nix für ungut. Es ist int-string und das ist es auch.
ein cin>>int>>string liefert dir hier int==123 und string==katzekatze678
genau das korrekte verhalten.Die Operatoren arbeiten schon korrekt weil konsistent. Die hier vorgeschlagenen anderen Erwartungen an den op>> sind ziemlich dämlich.
-
Kennst du irgendeine andere Sprache/Library, bei der "123katzekatze678" ein int und ein string ist?
-
o90o90o90o schrieb:
Kennst du irgendeine andere Sprache/Library, bei der "123katzekatze678" ein int und ein string ist?
Klar, jede Sprache.
Man hat normalerweise halt keine generischen extraktoren wie der op>> aber zB ein parseInt in JavaScript auf "123katze" liefert dir 123 als Ergebnis.
In Java funktioniert Scanner zB sehr ähnlich zum op>> in C++.
Eigentlich kenne ich keine Sprache wo "123katze" als integer interpretiert nicht 123 liefert. Kennst du eine?
-
Shade Of Mine schrieb:
Die Operatoren arbeiten schon korrekt weil konsistent. Die hier vorgeschlagenen anderen Erwartungen an den op>> sind ziemlich dämlich.
1. Nur weil etwas konsistent ist, ist es noch lange nicht korrekt.
2. Was ist daran überhaupt konsistent? int endet anscheinend bei jedem Zeichen, dass nicht als int interpretiert werden kann. string endet bei Whitespace. Das einzige was da konsistent ist, ist dass es nicht intuitiv ist.Shade Of Mine schrieb:
o90o90o90o schrieb:
Kennst du irgendeine andere Sprache/Library, bei der "123katzekatze678" ein int und ein string ist?
Klar, jede Sprache.
Man hat normalerweise halt keine generischen extraktoren wie der op>> aber zB ein parseInt in JavaScript auf "123katze" liefert dir 123 als Ergebnis.
In Java funktioniert Scanner zB sehr ähnlich zum op>> in C++.
Eigentlich kenne ich keine Sprache wo "123katze" als integer interpretiert nicht 123 liefert.
Ich hab zwar Java Scanner noch nie verwendet, aber habs mal getestet und 123katze ist kein int.
/* package whatever; // don't place package name! */ import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; /* Name of the class has to be "Main" only if the class is public. */ class Ideone { public static void main (String[] args) throws java.lang.Exception { Scanner scanner = new Scanner(System.in); int i = scanner.nextInt(); System.out.println(i); System.out.println("Bye..."); scanner.close(); } }ideone macht bei copy&paste die formatierung kaputt.

Success #stdin #stdout 0.1s 380736KB
comments (?)
stdin
copy123
stdout
copy123
Bye...Runtime error #stdin #stdout #stderr 0.1s 380672KB
comments (?)
stdin
copy123katze
stdout
Standard output is empty
stderr
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:909)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextInt(Scanner.java:2160)
at java.util.Scanner.nextInt(Scanner.java:2119)
at Ideone.main(Main.java:15)Kennst du eine?
Java

Ich hab jetzt keine Lust mehr auf den Quatsch und eure falschen Behauptungen zu überprüfen. Wenn ihr meint, dass 123katze ein int sein sollte, dann viel Spass bei euren Kunden.