Tastatur Puffer unter Linux leeren?

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

Tastatur Puffer unter Linux leeren?
Also, bin einfach nicht dahinter gekommen wie das gehen soll. Vielleicht weis ja jemand Abhilfe, falls das ueberhaupt geht.
Hier mal ein kleines Beispiel zum Problem (das wahrscheinlich jeder hatte, der in wsort fgets benutzte und Zeilen ueber 100 Zeichen wirksam rausfiltern wollte…):

#include <stdio.h>
#include <stdlib.h>
int main() {
	char tmp[8];
	int i;
	char *zeile;
	for(i=0; i<3; i++) {
		printf("Eingabe Zeile %d:\t<", i);
		zeile = fgets(tmp, 8, stdin);
		printf("Ausgabe Zeile %d:\t>", i);
		fputs(tmp, stdout);
	}
	return 0;
}

Jedenfalls, wenn eine Zeile nicht zu lang ist, ist es ja kein Problem:

faui06d [~/c]> fgetstest
Eingabe Zeile 0:        <Test
Ausgabe Zeile 0:        >Test
Eingabe Zeile 1:        <

Aber wenn die Zeile zu lang ist…

faui06d [~/c]> fgetstest
Eingabe Zeile 0:        <langer Test
Ausgabe Zeile 0:        >langer Eingabe Zeile 1:        <Ausgabe Zeile 1:       >Test
Eingabe Zeile 2:        < 

…nimmt fgets was er will und laesst den Rest im buffer. Das ist bloed, da der Rest in die naechste Eingabe reinrutscht.

Nadan, buffer leeren:
fflush(stdin);

Nur bewirkt das ja rein gar nix :#:

http://www.galileo-press.de/openbook/c_von_a_bis_z/c_018_012.htm#RxxobKap01801204002A221F02B18C

Der Positionszeiger fuer stdin ist auch nicht zu gebrauchen, der steht immer auf -1. Also nix mit fseek(), fsetpos(), rewind().
(soviel dazu, das stdin und eine Datei keinen Unterschied machen sollten…)

Gut, man kann das ja so hinnehmen und nachtraeglich eine grosse Eingabe von 120 oder 320 Zeichen reparieren…
Aber das muss doch nicht sein, das ist doch laestig…

Hat da jemand ne Loesung? :rolleyes:

(ausser "nimm halt fgetc()!)


Ich weiss nicht genau was hier wirksam sein soll. In der manpage von fgets steht doch ganz klar dass er maximal soviele Buchstaben liest wie Du ihm sagst, und nicht dass er danach noch den Rest der Zeile liest und verwirft.
Das wirst Du schon selber erledigen muessen…

fflush ist auch zum flushen (im Sinne von an write uebergeben) von Puffern fuer Ausgabestreams da und nicht um den Rest der Zeile eines Eingabestreams zu flushen (im Sinne vom im Klo runterspuelen). Auch das kann man der manpage entnehmen.

http://www.galileo-press.de/openbook/c_von_a_bis_z/c_018_012.htm#RxxobKap01801204002A221F02B18C
Kein Kommentar zu diesem Buch…
Edit: Die Problemstellung in dem Buch ist eine voellig andere. Waehrend Du den Rest der Zeile verwerfen willst, will man in dem Buchbeispiel ein Zeichen lesen ohne dass zunaechst eine Newline Zeichen kommen muss. Da der Terminaltreiber unter Linux puffert nutzt es nichts selbst wenn der puffer der c-bibliothek geleert ist, weil diese die Zeichen auch nicht bekommt. Hierzu muss man den Terminaltreiber verstellen. Aber wie gesagt hat das mit Deinem Problem wenig gemein.

Natuerlich macht es einen Unterschied ob man aus einer Datei oder z.B. einer Tastatur liest, oder einem Netzwerksocket, oder… Eine Datei ist auf der Platte gespeichert und man kann jederzeit wieder von vorne lesen. Wenn die Daten aber nicht persistent irgendwo vorliegen sondern wirklich Stromartig kommen muessen die Daten irgendwo gepuffert werden - und Puffer sind nicht endlos gross…

So schwer ist das nicht, und aufgrund obiger Probleme wirst Du Dir diese Muehe wohl machen muessen. Uebrigens habe ich gerade einen wsort korrigiert der zuerst alle Woerter gezaehlt hat, dann mit rewind den Stream zurueckgesetzt und Puffer fester Groesse allokiert in die er gelesen hat. Nur leider funktioniert das mit
cat wlist5 | ./wsort
nicht mehr, weil die wlist5 zu gross fuer die Puffer ist…


Wenn Dich das genaue Pufferverhalten der libc interessiert kannst Du es uebrigens in der manpage stdio(3) nachlesen…


Hallo,
Was zu dem was ich dir vorhin nach SoS gesagt habe: Das fflush was bei mir zu (ich sag mal) 90% ging (hatte es eigentlich auch getestet) scheint auch bei mir jetzt nicht mehr zu gehen… Bäh, somit hab ich nen Fehler in meiner Aufgabe!

Alles was mir zu sagen bleibt ist, dass ich es ziemlich bescheiden finde, dass man uns sagt, wie sollen die Funktion nehmen, ohne uns auf dieses Problem hinzuweisen oder uns weitere Informationen zu geben. Ohne den Hinweis nehmt fgets, hätte ich wohl Zeichenweise eingelesen…

Kann man nichts machen, wir sind machtlos :-/


In den Folien zur C-Einfuehrung sind alle moeglichen Funktionen zur Ein-/Ausgabe, darunter auch fgets. Zeichenweise lesen ist auch kein Problem. Ich weiss nicht, wer euch gesagt hat, dass ihr “die Funktion” (fflush?) nehmen muesst, aber auf dem Aufgabenblatt kann ich dazu keinen Hinweis finden. Wie gesagt, Ein-/Ausgabe wird in praktisch jeder Aufgabe gebraucht und ist absolutes Grundwissen, daher finden sich hierzu auch keine gesonderten Hinweise auf den Aufgabenblaettern. Und ob ihr dazu nun fgets, scanf, getchar oder was auch immer verwendet ist eure Sache und wir wollen es auch nicht vorschreiben…

Btw seid ihr ueberhaupt nicht machtlos, es kommt einfach vor, dass wir an manche Dinge nicht denken. Dafuer gibt es dann auch Rechneruebungen, in denen man Dir sicher haette sagen koennen warum Dein Programm nicht funktioniert, und Dir auch Tipps geben wie man die Eingabe am Besten loest.


Naja, habe sogar die manpage von fgets gelesen; Nur steht da natürlich nix detailiertes über den stream… Naja, habe das einfach falsch verstanden. Das nächste mal Frage ich einfach in ner Rechnerübung, versprochen :wink:

Schande über mein Haupt, habe es gerade in der manpage gelesen…
Habe mich von „c von a bis z“ verleiten lassen das mal auszuprobieren.

Danke auch noch für die anderen Erklärungen!

Bin jetzt aber irgendwie neugierig wie/ob ich auf den streambuffer komme um da drinnen rumzupfuschen :smiley:

Nee, habe jetzt erstmal genug davon. Zurück zum wesentlichen und an den Aufgaben arbeiten…

Tja, was soll ich sagen: Fragezeichen… Habe auch immer Lobpreisungen über fgets gehört. Aber durch das gepufferte einlesen muss man bei zu langen Zeilen dermassen Kopfstände machen, dass es einfacher gewesen wäre fgetc zu verwenden - so geht es zumindest mir.
Aber Zeichenweise ist ungepuffert, also wieder langsam… hmpf…

So, widme mich wieder der kleinen shell. Diesmal aber mit fgetc… :wink:

Edit:

Da fällt mir gerade noch was ein:
Das Problem war den Aufgabenstellern wahrscheinlich bekannt, da auf dem Aufgabenblatt darauf hingewiesen wird, wie bei Zeilen > 100 Zeichen zu verfahren ist, aber in keiner Testdatei eine Zeile > 100 Zeichen enthalten ist:

:smiley:


Neeeein das geht doch mit fgets viel leichter, zumal in der Shell doch steht, dass die Zeile maximal 1024 Zeichen lang ist. So schlimm ist es auch nicht die Zeile fertig zu lesen, siehe z.B.
http://wwwcip.informatik.uni-erlangen.de/~simistil/Beispiel_Loesungen/aufgabe2-wsort/src/wsort.c

fuer ein wsort Beispiel, das mit fgets die Zeile fertig liest.

Falls Dich das mit der ungepufferten Eingabe wirklich interessiert kannst Du Dir
http://wwwcip.informatik.uni-erlangen.de/~simistil/Beispiel_Loesungen/aufgabe8-bbuffer-semaphor-shm/src/unbuf_io.c
mal anschauen, spielt aber in den derzeitigen Aufgaben keine Rolle und ist auch in der betreffenden Aufgabe eher ein Schmankerl :wink:


Oha, ist ja wirklich gar nicht so wild!

:cheesy:


ich glaub auch dass man hätte weniger Stress, wenn man einfach fgetc benutzt hätte :wink: außerdem, bei fgets ist es notwendig, Wortlänge zu überprüfen-> nochmal durch das Wort rasen->bisschen Performance verlieren.


Nicht wirklich. Mit fgets geht’s schneller und einfacher - wenn man weiß wie. :wink: Siehe dazu z.B. die Lösung von Mikey (da fehlen aber ein paar Fehlerabfragen. Ts ts ts. :-p).

Hm, nö. Das geht auch ohne durch das komplette Wort zu gehen. Man muss nur mal überlegen, woran man erkennt, dass fgets eine zu lange Zeile gefunden hat… Dann kann man anhand eines Buchstabens prüfen, ob die gesamte Zeile gelesen wurde oder nicht.


Also so kann man den buffer löschen:

#include <stdio_ext.h>
(...)
__fpurge(stdin);

:cheesy:

Hat aber nen kleinen Schönheitsfehler:

Nix mit ANSI C…
:cry:

Natürlich muss die manpage noch spitzfindig einen draufsetzen:

:#:
Für gewöhnlich ein Fehler? Und warum hat sich jemand die Mühe gemacht die Funktionen für BSD und Solaris zu implementieren?