Frage zum löschen des Inputpuffers
-
Hallo,
ich habe folgendes Programmbeispiel und verstehe die Zeile
while ((clear_puffer = getchar()) != EOF && clear_puffer != '\n');
nicht ganz. Offenbar wird hier der Tastaturpuffer gelöscht? Warum nicht mit fflusch(stdin); ?
Kann mir bitte jemand erklären was die Programmzeile hier für einen Sinn macht?
Hier der gesamte Code:
#include <stdio.h> int main(void) { int zahl; printf("Bitte geben Sie eine Zahl ein\n"); printf("Mit 0 wird das Programm beendet! "); scanf("%i",&zahl); while (zahl != 0) { printf("Das Quadrat von %i = %i\n",zahl, zahl*zahl); printf("Naechste Zahl: "); scanf("%i",&zahl); } int clear_puffer; while ((clear_puffer = getchar()) != EOF && clear_puffer != '\n'); getchar(); return 0; }
-
ledi schrieb:
ich habe folgendes Programmbeispiel und verstehe die Zeile
while ((clear_puffer = getchar()) != EOF && clear_puffer != '\n');
nicht ganz. Offenbar wird hier der Tastaturpuffer gelöscht?
Nein, es wird solange von stdin gelsen, bis ein Zeilenumbruch oder das Streamende erreicht wird. Die dabei gelesenen Zeichen werden anscheinend verworfen. Der Name clear_puffer ist nicht nur vom Denglisch her ungünstig gewählt. Es gibt keinen Tastaturpuffer (zumindest keinen, den dein Programm mit Standardmitteln erreichen kann), es gibt nur einen langen Strom von Zeichen, der von irgendwoher (das ist im Allgemeinen nicht die Tastatur!) an dein Programm weitergegeben wird. Ein C-Programm ist wie eine schwarze Kiste, in die ein Lochstreifen mit Zeichen reingeht (stdin) und zwei rausgehen (stdout und stderr), dein Programm kann nur innerhalb der Kiste mit den Lochstreifen arbeiten, was davor und danach kommt, darauf hat es (ohne Betriebssystemfunktionen aufzurufen) keinen Einfluss.
Warum nicht mit fflusch(stdin); ?
Weil dies im Allgemeinen undefiniertes verhalten auslöst. Es gibt einen speziellen Compiler für ein spezielles System, wo dies das macht, was du denkst, überall sonst wird dieser Funktionsaufruf verrückte Sachen machen.
Kann mir bitte jemand erklären was die Programmzeile hier für einen Sinn macht?
Unter der Annahme, dass die in Zeile 15 gelesene Zahl von einem weiteren Zeichen (z.B. einem Zeilenumbruch) gefolgt war, soll das getchar in Zeile 20 erst auf ein Zeichen nach diesem Zeilenumbruch reagieren. Das klingt nicht sehr sinnvoll, jedoch falls das Programm seine Eingaben über eine Tastatur bekommt, hätte diese Zeile zur Folge, dass nach der Eingabe einer Zahl für Zeile 15 noch eine weitere Eingabe getätigt werden muss (die dann mit i.d.R. mit der Entertaste abgeschlossen wird), damit das Programm endet.
-
hi.
ledi schrieb:
Offenbar wird hier der Tastaturpuffer gelöscht?
ja, die zeile soll den eingabepuffer löschen.
(ich sehe keine probleme darin, den seit jahrzehnten üblicherweise gewählten begriff puffer auch weiterhin zu benutzen. die zeichen werden während der eingabe gepuffert).in der schleife werden die zeichen mit getchar solange einzeln aus dem puffer eingelesen, bis ein EOF oder ein '\n' zurückgegeben wird und die schleife abbricht. danach hat man für weitere eingaben einen leeren, sauberen puffer.
man könnte sich jetzt fragen, wie das '\n' in den puffer überhaupt hinein kommnt.
tja, das ist die eigenschaft von schanf, getchar und zum teil auch von fgets. scanf/getchar schreiben beim abschluss einer eingabe, also wenn man die enter-taste drückt, das '\n' an das ende des puffers.
zu programmstart ist der puffer nämlich leer. das kann man überprüfen, indem manint c; while ((c = getchar()) != EOF && c != '\n') ;
an den anfang des programms schreibt, das programm startet und feststellt,
das man aus der schleife nur dann herauskommt, wenn man die enter-taste drückt.ledi schrieb:
Warum nicht mit fflusch(stdin); ?
Kann man machen, funktioniert aber nicht auf jedem system und ist daher
nicht standardgemäß. fflusch(stdin) kann auf manchen systemen zu undefiniertem verhalten führen. darum geht man gern standardkonforme wege.ledi schrieb:
Kann mir bitte jemand erklären was die Programmzeile hier für einen Sinn macht?
in deinem programmbeispiel macht die zeile m.m.n. offengestanden genau 0 sinn.
-
ok,
d.h. ich muss einen inputstream genau so (und nur so) beenden?
Gibt es auch andere Varianten?
Oder wie würdest du das hier in diesem konkreten Beispiel lösen?
-
ledi schrieb:
ok,
d.h. ich muss einen inputstream genau so (und nur so) beenden?
Nein. Was meinst du überhaupt mit Beenden?
Gibt es auch andere Varianten?
Es gibt immer viele Wege. Wenn es um das "Problem" der Mischung formatierter und unformatierter Eingabefunktionen geht, dann sollte man sich zum Beispiel mal die Feinheiten des scanf-Formatstrings angucken, was dort so alles möglich ist.
Oder wie würdest du das hier in diesem konkreten Beispiel lösen?
Ich würde Zeilen 20 und 21 komplett weglassen. Wenn man ein Konsolenprogramm ausführen will, dann nehme man eine Konsole. Und wenn man eine Konsole genommen hat, dann nervt so etwas wie Zeile 20 und 21 nur, weil es genau das umgekehrte Verhalten erzeugt, das man normalerweise von einem Konsolenprogramm erwartet.
-
Der Puffer wird nicht gelöscht.
Es werden nur die Zeichen bis zum nächsten '\n' (oder EOF) gelesen.Alle weiteren Zeichen bleiben im Puffer.
Die meisten IDEs bieten die Möglichlkeit die Konsolenfenster offen zu lassen, bzw. nochmal anzeigen zu lassen.
Daher ist dein getchar gar nicht nötig.
-
das programm startet doch mit einem leeren puffer, warum sollte es in diesem fall weitere zeichen vor dem scanf aufruf geben?
-
b.b. schrieb:
das programm startet doch mit einem leeren puffer, warum sollte es in diesem fall weitere zeichen vor dem scanf aufruf geben?
Nochmal: Es gibt keinen Puffer!
Das ist ein komplett falsches Bild davon, was da abläuft und alle komplexeren Folgerungen daraus sind falsch. Du hast eine Kette von Zeichen, die geht in dein Programm rein und da kannst du nix dran ändern, du kannst nur unterschiedlich darauf reagieren. Dein Programm steuert nicht die Tastatur und auch nicht den Monitor, das machen andere Programme mehrere Abstraktionsschichten über der C-Runtime, die sind dann so nett die Zeichen von der Tastatur an dein Programm weiterzuleiten oder die Ausgabe deines Programms auf dem Monitor zu zeigen. Auf der Ebene deines Programms ist ein eventueller Tastaturpuffer längst Geschichte, weil der ganz woanders sitzt. Wenn eine der Abstraktionsebenen zwischen deinem Programm und der Tastatur entscheidet, dass dein Programm nicht mehr Zeichen von der Tastatur sondern aus einer Datei erhalten soll, dann bekommt dein Programm die Zeichen daher und dein Programm kann den Unterschied nicht feststellen! Das ist auch kein exotischer Vorgang, das Umleiten der Standard-Ein- und Ausgabe ist das kleine Einmaleins für jeden der ein unixoides System ernsthaft benutzt. Die Quelle der Zeichen ist auch nicht unbedingt gepuffert, die ganze Frage macht daher einfach keinen Sinn.
-
die über die tastatur eingegebenen zeichen müssen irgendwo zwischengespeichert werden, bevor sie mit getchar oder scanf abgeholt werden.
dieser zwischenspeicher wird üblicherweise puffer genannt, vermutlich entnommen aus dem englischen wort buffer.
(ein strom wird es erst dann, wenn ich die enter-taste drücke, dann wird - wuuuuusch - der inhalt aus dem puffer nach stdin "geströmt".)das ist doch bloß eine frage der interpretation.
die ganze c-welt benutzt das wort puffer/buffer, ich weiß gar nicht warum du da jetzt so einen hermann von machst.wenn die quelle gar nicht gepuffert wäre (was nicht heißen soll, dass sie gepuffert sein muss), dann hätten wir das problem des puffer-leerens gar nicht erst und es wäre kein "restmüll" im puffer nach einem scanf-aufruf. :p
-
Deine Vorstellung ist komplett falsch. scanf funktioniert so nicht. stdin funktioniert so nicht. Noch einmal erklär ich es dir aber nicht. Fall eben auf die Schnauze mit deinen falschen Vorstellungen, wenn du nicht lernen möchtest.
-
komplett falsch, soso, interessant. du willst mir also erzählen, dass die tastatureingabe nicht zwischengespeichert wird.
also, ich habe z.b.
int number; scanf("%d", &number);
der benutzer gibt z.b. ein: 123 und dann drückt er die eingabetaste.
für mich ist es jetzt klar, dass die zeichen '1', '2', '3' irgendwo
zwischengespeichert(gepuffert) werden müssen, bevor sie von scanf interpretiert und nach erfolgreicher auswertung und umwandlung als eine
dezimalzahl in der übergebenen variable number gespeichert werden -
für dich ist dieser puffer(zwischenspeicher) ein magic-stream.
das ist völlig im ordnung, jeder hat so seine eigene vorstellung. :pbtw. lerne ich sehr gern dazu, ich weiß gar nicht wie du auf das schmale brett kommst, dass dem nicht so wäre.
-
Wenn da ein Puffer ist, dann zeig mal, wie man ihn löscht.
-
SeppJ schrieb:
Wenn da ein Puffer ist, dann zeig mal, wie man ihn löscht.
gern.
int c; while ((c = getchar()) != EOF && c != '\n') ;
wenn zeichen noch im puffer waren, sind sie nach dem
abarbeiten der schleife nicht mehr per getch, scanf, fgets, etc. zugänglich.
ob die zeichen wirklich noch im puffer stehen, oder intern lediglich ein zeiger verbogen wurde, ist prinzipell wurst.
für den anwendungsprogrammierer hat das den effekt einer pufferleerung
(oder von mir aus auch eines leeren zeichenstroms).
-
Der "Puffer" wird nicht geleert.
Eingabe1 einige Zeit warten (oder lange Berechnung) Puffer leeren Eingabe2
Wenn der Puffer geleert wird, sollte nichts von den Eingaben während der Wartezeit bei der Eingabe2 auftauchen.
Bei dem
while ((c = getchar()) != EOF && c != '\n');
wird aber nur bis zum ersten '\n' aus dem Stream gelesen. Der Rest bleibt drin.
-
Und du glaubst wirklich, dass ich nicht genau diese falsche Antwort erwartet habe?
Dieses Programm löscht eine Zeile, ganz egal wann oder wie diese eingegeben wurde. Ist keine ganze Zeile da, dann wartet es, bis irgendwoher ein Zeilenumbruch kommt. Nix vonwegen Puffer löschen, die Zeile muss sogar eventuell noch eingegeben werden und wird dann ignoriert!
-
Der Rest bleibt drin.
kann man denn ein beispiel programmieren/konstruieren, bei dem das so ist?
das also nach der ausführung der while schleifewhile ((c = getchar()) != EOF && c != '\n');
noch weitere zeichen mit getchar, scanf, fgets etc. eingelesen und angezeigt werden können?
-
b.b. schrieb:
kann man denn ein beispiel programmieren/konstruieren, bei dem das so ist?
-
SeppJ schrieb:
b.b. schrieb:
kann man denn ein beispiel programmieren/konstruieren, bei dem das so ist?
haha, sehr witzig!
-
b.b. schrieb:
kann man denn ein beispiel programmieren/konstruieren, bei dem das so ist?
das also nach der ausführung der while schleifewhile ((c = getchar()) != EOF && c != '\n');
noch weitere zeichen mit getchar, scanf, fgets etc. eingelesen und angezeigt werden können?
Setzt meinen Pseudocode in C um.
Direkt nach der ersten Eingabe drückst du die Entertaste mehrmals.
-
DirkB schrieb:
Direkt nach der ersten Eingabe drückst du die Entertaste mehrmals.
dadurch schreibt scanf wieder ein \n in den puffer rein, ist doch klar das der puffer dann nicht mehr leer ist.