011
04.11.2007, 15:00 Uhr
0xdeadbeef
Gott (Operator)
|
Vielleicht nicht so sehr ein Bug wie ein Microsoftismus, unter Windows ist das sogar definiert. Allerdings - laut Standard lassen sich, eigentlich offensichtlicherweise, nur Ausgabeströme flushen, das heißt, fflush(stdin); kann standardkonform alles mögliche machen - abstürzen, nichts tun, den Eingabestrom flushen oder sogar die Festplatte formatieren. Wobei das letztere eher unwahrscheinlich ist.
So oder so, dass es dir den Eingabestrom flusht ist keinesfalls garantiert, und es ist auch eigentlich eher selten wünschenswert - stell dir vor, jemand füttert dir nach stdin ne Datei, dann kriegt das Programm nachher nie mehr Input von stdin.
Sinnvoller ist es, die Eingabe zeilenweise zu verarbeiten, in C mit fgets, in C++ mit std::getline. Das sieht dann so aus:
C++: |
#include <stdio.h>
int main(void) { char buf[100]; // 100 == maximale Zeilenlänge in diesem Beispiel int x, y;
printf("Zahl x eingeben: "); // stdout ist ein Ausgabestrom, das hier sorgt für sofortige Ausgabe unter // allen Umständen. Hier nicht wirklich notwendig, da stdout und stdin aneinander // gebunden sind, aber so zur Demonstration: fflush(stdout);
fgets(buf, 100, stdin); sscanf(buf, "%d", &x);
printf("Zahl y eingeben: "); fflush(stdout);
fgets(buf, 100, stdin); sscanf(buf, "%d", &y); printf("x = %d, y = %d\n", x, y);
return 0; }
|
Das sieht dann in der Benutzung z.B. so aus:
C++: |
$ ./a.out Zahl x eingeben: 1 2 Zahl y eingeben: 3 x = 1, y = 3
|
Zu beachten ist noch, dass fgets am Ende das newline-Zeichen erhält. Das ist für das Parsen mit sscanf nicht weiter von Bedeutung, kann aber bei der Ausgabe ungewollt lustige Effekte haben, mit Extra-Newlines und so, deswegen erwähne ich es hier.
Du kannst das ganze auch in eine eigene Funktion gießen, mit ein bisschen C-Magie:
C++: |
#include <stdarg.h> #include <stdio.h>
int linewise_scanf(FILE *stream, char const *fmt, ...) { va_list va; char buf[1024]; int rc;
// fgets gibt NULL zurück, wenn beim Einlesen ein Fehler auftrat // In dem Fall, nach scanf-Konvention, geben wir die Anzahl der // eingelesenen Elemente - null - zurück if(NULL == fgets(buf, 1024, stream)) { return 0; }
va_start(va, fmt);
rc = vsscanf(buf, fmt, va);
va_end(va);
return rc; }
int main(void) { char buf[100]; // 100 == maximale Zeilenl�nge in diesem Beispiel int x, y;
printf("Zahl x eingeben: "); fflush(stdout);
linewise_scanf(stdin, "%d", &x);
printf("Zahl y eingeben: "); fflush(stdout);
linewise_scanf(stdin, "%d", &y);
printf("x = %d, y = %d\n", x, y);
return 0; }
|
...in C++ wär das halt
C++: |
#include <iostream> #include <sstream> #include <string>
int main() { std::string line; std::istringstream is; int x;
std::cout << "Zahl eingeben: " << std::flush;
std::getline(std::cin, line); is.str(line); is >> x;
std::cout << "x = " << x << std::endl; }
|
Nachtrag:
Es böte sich hier natürlich an, zusätzlich noch eine Zeilen-Einlese-Funktion zu schreiben, die nicht auf einen festen Buffer angewiese ist, wie GNUs getline. Aber 1024 Zeichen sollten für vertrauenswürdige Umgebungen in aller Regel ausreichen. -- Einfachheit ist Voraussetzung für Zuverlässigkeit. -- Edsger Wybe Dijkstra Dieser Post wurde am 04.11.2007 um 15:04 Uhr von 0xdeadbeef editiert. |