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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.