Hallo,
diesmal geht's darum, drei Zeichen mit scanf einzulesen. Ich habe zwei
Versionen, wobei Version 1 nicht geklappt hat. Dann habe ich weiter
ausprobiert und kam auf die zweite Version, in dem ich alle Zeichen auf
einmal eingelesen habe. Wo liegt der Fehler bei der ersten Version?
Mein erster Versuch:
Der Fehler bei deinem ersten Versuch liegt darin, dass du ja nicht 3
Zeichen eingibst, sondern deren 6.
Du tippst natürlich die 3 Zeichen, die du eingeben willst. Aber: Du
tippst dazwischen bzw. nach dem letzten ja auch jedesmal auf 'Return'.
Und auch dieses jeweilige Return ist ein Zeichen, das du bzw. das
Programm behandeln musst. Es wird dir ganz normal als eine gültige
Eingabe für %c geliefert.
Achso Dankeschön :)
Nur eine Sache, die ich nicht ganz verstehe, warum kommt es bei Nutzung
von int und Eingabe von ganzen Zahlen nicht zu dieser Pufferung?
Leyla S. schrieb:> Achso Dankeschön :)> Nur eine Sache, die ich nicht ganz verstehe, warum kommt es bei Nutzung> von int und Eingabe von ganzen Zahlen nicht zu dieser Pufferung?
Weil ein %d sich automatisch soweit vortastet, bis es zu einer Zahl
kommen kann. D.h das %d überliest selbsttätig den Return und eventuelle
andere Leerzeichen (sog. Whitespace-Zeichen).
Ein %c tut das aber nicht. Der liefert dir genau das nächste Zeichen,
welches im Eingabestrom daher kommt.
Leyla S. schrieb:> Okey danke für den Hinweise mit fflush(stdin). Das erste klappt jetzt:)
Ist aber genau genommen nicht garantiert, auch wenn viele
Implementierungen das so handhaben.
fflush ist eigentlich nur für Ausgabe-Streams definiert. Was passiert,
wenn man fflush auf einen Eingabe-Stream anwendet ist
implementierungs-abhängig.
Karl Heinz schrieb:> Leyla S. schrieb:>> Okey danke für den Hinweise mit fflush(stdin). Das erste klappt jetzt:)>> Ist aber genau genommen nicht garantiert, auch wenn viele> Implementierungen das so handhaben.> fflush ist eigentlich nur für Ausgabe-Streams definiert. Was passiert,> wenn man fflush auf einen Eingabe-Stream anwendet ist> implementierungs-abhängig.
Schlimmer noch: Es ist sogar undefined Behavior. fflush sollte deswegen
überhaupt nicht auf Eingabeströme angewandt werden.
Hier der entsprechende Auszug aus dem Standard:
1
Description
2
3
If stream points to an output stream or an update stream in which the
4
most recent operation was not input, the fflush function causes any
5
unwritten data for that stream to be delivered to the host environment
6
to be written to the file; otherwise, the behavior is undefined.
7
8
If stream is a null pointer, the fflush function performs this flushing
9
action on all streams for which the behavior is defined above.
Auf meinem Linux-Rechner hier passiert bei fflush(stdin) einfach gar
nichts, aber selbst ein Systemabsturz bei diesem Aufruf wäre
standardkonform.
Hier sind noch zwei FAQs (mit Antworten ;-)) zu dem Thema:
http://c-faq.com/stdio/stdinflush.htmlhttp://c-faq.com/stdio/stdinflush2.html
Im konkreten Fall kann man das CR-Zeichen und ggf. weiteren Whitespace
dadurch überlesen, dass man in den Formatstrings jeweils vor dem %c noch
ein Leerzeichen einfügt:
1
scanf(" %c",&x);
Damit kann man dann allerdings auch keine Leerzeichen mehr einlesen. Da
scanf alle Whitespace-Zeichen (Leerzeichen, Tab, CR, LF usw.) gleich
behandelt, ist es zum Einlesen von solchen Zeichen ziemlich ungeeignet.
Man nimmt dann lieber getchar (zum Einlesen einzelner Zeichen) oder
fgetc (zum Einlesen ganzer Zeilen).
Rainer V. schrieb:> fflush(stdin)
Das wird zwar manchmal gerne gemacht, ergibt aber eigentlich überhaupt
keinen Sinn und ist in C auch nicht definiert.
Yalu X. schrieb:>> fflush ist eigentlich nur für Ausgabe-Streams definiert. Was passiert,>> wenn man fflush auf einen Eingabe-Stream anwendet ist>> implementierungs-abhängig.>> Schlimmer noch: Es ist sogar undefined Behavior.
War mir nicht mehr sicher.
> Man nimmt dann lieber getchar (zum Einlesen einzelner Zeichen) oder> fgetc (zum Einlesen ganzer Zeilen).
Du meinst wohl fgets
So haben wir das im Grunde auch meistens gehandhabt. Mit fgets eine
Zeile einlesen und dann mit sscanf oder sonstigen Mittel zerlegen. scanf
bzw. fscanf können zwar benutzt werden, wenn man genau definierte
Eingaben hat, aber im Grunde ist eine fgets/parsing Kombination meistens
sicherer.
Wobei sich mit den 'neueren' Formatieroptionen da auch einiges geändert
hat. Aber wie es so schön heisst: Ein alter Hund lernt keine neuen
Tricks mehr. "fgets, dann parsing" hat sich bei mir bewährt. Sofern
nicht überhaupt plattformspezifische Methoden zum Zug kommen müssen,
weil so Dinge wie Funktionstasten od. Cursortasten da auch noch
mitgenommen werden müssen.