Forum: PC-Programmierung C: ungetc(.) für read-only files


von komisch (Gast)


Lesenswert?

Hallo,

ungetc() funktioniert auch mit Files, die im read-only-Modus geöffnet 
wurden. Sehe ich das richtig?

Und man kann sogar Buchstaben zurückschieben, die gar nicht da waren? 
Bei einem read-only-File?
1
   FILE* fp = fopen ("text.txt", "r");
2
3
   int ch;
4
5
   for (int i = 0; i < 5; i++) {
6
      if ((ch = getc (fp)) != EOF) {
7
         putchar (ch);
8
      }
9
10
      ungetc (ch, fp);
11
   }
12
13
   for (int i = 0; i < 5; i++) {
14
      if ((ch = getc (fp)) != EOF) {
15
         putchar (ch);
16
      }
17
18
      ungetc ('5', fp);  //was anderes zurückschreiben
19
   }

Irgendwie ist das komisch und unlogisch. Das "funktioniert" so, weil da 
alles gepuffert ist oder?

von Nick M. (Gast)


Lesenswert?

komisch schrieb:
> ungetc (ch, fp);

ungetc pushes the char back into the file buffer.
ungetc does not change the file on disk.

Es hilft also, das Handbuch zu lesen.

von immer noch komisch (Gast)


Lesenswert?

Nick M. schrieb:
> ungetc pushes the char back into the file buffer.
> ungetc does not change the file on disk.
>
> Es hilft also, das Handbuch zu lesen.

Ja, aber das ist doch unlogisch. Warum kann ich etwas zurückschieben, 
was in diesem read-only-File gar nicht da war.

Wäre es nicht besser so ein Puffer auch als read-only zu definieren? Und 
die gelesene Variable intern zu speichern?

So dass der Aufruf von ungetc() diese Variable zurückschiebt (und nicht 
was Beliebiges).

von g457 (Gast)


Lesenswert?

> Wäre es nicht besser so ein Puffer auch als read-only zu definieren?

Nein, natürlich nicht.

HTH

von komisch (Gast)


Lesenswert?

Warum ist es schlecht eine interne Variable zu haben, die dann per 
ungetc()-Aufruf zurückgesetzt werden kann? Und dadurch verbieten, dass 
der User alles Mögliche zurückschiebt? (quase als read-only definieren)

Wenn ich alles richtig verstanden habe, dann wird vom C-Standard nur ein 
ungetc()-Aufruf unterstützt. Aber eben nicht zwanzig Aufrufe 
hintereinander. Also reicht eine interne Variable.

Welchen Sinn macht es dem User zu urlauben alles Mögliche auf den Stream 
zu legen? Er soll nur das drauf legen können, was auch vorher ausgelesen 
wurde.

von Heiner (Gast)


Lesenswert?

immer noch komisch schrieb:
> Warum kann ich etwas zurückschieben,
> was in diesem read-only-File gar nicht da war.

Weil es nützlich ist. Stark vereinfachtes Beispiel: Ein Parser für 
Rechenausdrücke. Du liest "5+3" und schiebst 8 zurück in den Puffer. 
Dieses Verfahren wird wiederholt angewendet, bis der ganze Puffer 
ausgewertet ist.


immer noch komisch schrieb:
> Wäre es nicht besser so ein Puffer auch als read-only zu definieren? Und
> die gelesene Variable intern zu speichern?

Wenn es nur darum geht, ein paar Zeichen "in die Zukunft zu sehen", 
könnte man das so machen, aber warum sollte man das auf diese Art fest 
verdrahten? Wenn du die Gewissheit brauchst, dass im Puffer jederzeit 
nur das enthalten ist, was auch in der Datei enthalten war, benutzt du 
diese Funktion einfach nicht oder nur in der von dir beschriebenen Art - 
Problem gelöst.

von foobar (Gast)


Lesenswert?

Du hast einfach nicht verstanden, wozu ungetc da ist.  Mit Schreiben in 
eine Datei hat es gar nichts zu tun, es geht um look-ahead.

Probier doch einfach mal, eine Routine zu schreiben, die ein Zahl (nicht 
eine einzelne Ziffer) einliest (wie es z.B. scanf-%d macht).  Du merkst 
dann ganz schnell, dass du sowas wie ungetc brauchst.

von foobar (Gast)


Lesenswert?

PS: In fast allen Fällen, wo ungetc benutzt wird, wird exakt der Wert 
zurückgegeben, der vorher gelesen wurde.

von PittyJ (Gast)


Lesenswert?

foobar schrieb:
> Du hast einfach nicht verstanden, wozu ungetc da ist.  Mit Schreiben in
> eine Datei hat es gar nichts zu tun, es geht um look-ahead.
>
> Probier doch einfach mal, eine Routine zu schreiben, die ein Zahl (nicht
> eine einzelne Ziffer) einliest (wie es z.B. scanf-%d macht).  Du merkst
> dann ganz schnell, dass du sowas wie ungetc brauchst.

Ich programmiere jetzt 30 Jahre in C/C++. Aber das ungetc() habe ich 
noch nie gebraucht, und in anderen Sourcecodes auch nie gesehen.
Das lässt sich meist eleganter lösen.

von udok (Gast)


Lesenswert?

PittyJ schrieb:
> Ich programmiere jetzt 30 Jahre in C/C++. Aber das ungetc() habe ich
> noch nie gebraucht, und in anderen Sourcecodes auch nie gesehen.
> Das lässt sich meist eleganter lösen.

Und wie?  Du kannst natürlich fseek verwenden... aber die Performance
ist dann im Eimer.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ja, man kann ungetc() immer vermeiden. Kommt auf die Architektur des 
Parsers an.

Aber ungetc() kann durchaus nützlich sein, nämlich dann, wenn eine 
Subroutine im Parser "zu weit" liest und dann feststellt: "Upps, das 
Zeichen geht mich nichts mehr an, also schiebe ich das zurück. Meine 
Unteraufgabe ist damit erledigt!"

Wenn dabei direkt noch eine Ersetzung erfolgen soll, wie zum Beispiel 
das Standardisieren von Whitespaces (TAB <-> SPACE), um es dem Parser 
einfacher zu machen, dann kann auch das Zurückschieben eines anderen 
Zeichens nützlich sein.

Fazit:

ungetc() ist nicht jedermans Freund - auch nicht meiner. Aber ihm 
deshalb eine Nützlichkeit generell abzusprechen, wäre falsch.

: Bearbeitet durch Moderator
von Dymo Fond (Gast)


Lesenswert?

PittyJ schrieb:
> Ich programmiere jetzt 30 Jahre in C/C++. Aber das ungetc() habe ich
> noch nie gebraucht, und in anderen Sourcecodes auch nie gesehen.
> Das lässt sich meist eleganter lösen.

Ja. Ich gehe mal davon aus, dass du mehrfach einen eigenen Puffer 
implementiert hast, natürlich einen besonders eleganten, statt einfach 
ungetc() zu nehmen.

Jeder wie er mag. Aber weißt du was? Ich fühle mich nicht schlecht wenn 
ich ungetc() verwende. Spart etwas Arbeit.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.