3

In my current understanding, you're supposed to call ungetc when you want to "un-get" the most recent character that you got from the stream, sort of like reversing the effect of an equivalent call to fgetc. If that's the case, then what's the point of having a parameter to specify which character to put back? Shouldn't the stream remember at least what its most recently obtained character was?

I was thinking that it could be just ungetc(stream), which probably makes more sense. I've seen a lot of implementations that involve the use of ungetc, and so far, none of them have really shown that the function is capable of pushing back a different character and explain how this behavior can be useful.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
AJ Tan
  • 193
  • 7
  • 2
    I've certainly used `ungetc()` to push back other characters. One problem is that you're only guaranteed one character of pushback and some implementations only allow that. Other implementations allow quasi-unlimited amounts of pushback (not less than 4 KiB). See [`ungetc()` — number of bytes of pushback?](https://stackoverflow.com/q/7814816/15186) for some details on this. Note that HP-UX is functionally dead, and I tested Solaris 10 and AIX 6 (so Solaris 11 and AIX 7 may have more pushback, and if so, it's probably the result of pushback from programmers). I've not tested Windows. – Jonathan Leffler May 21 '23 at 17:17

2 Answers2

4

In my current understanding, you're supposed to call ungetc when you want to "un-get" the most recent character that you got from the stream,

That is the use implied by the function's name, yes. And in my personal experience, it is the most common use, though this is a rarely-used function overall.

Shouldn't the stream remember at least what its most recently obtained character was?

It could, but I don't see how you get from there to should. The possibility of an alternative design for rarely-used ungetc() is pretty much the only reason for considering that.

I was thinking that it could be just ungetc(stream), which probably makes more sense.

It would make more sense if the function were limited to pushing back only the character most recently read from the specified stream. But in fact, there is no such limitation.

I've seen a lot of implementations that involve the use of ungetc, and so far, none of them have really shown that the function is capable of pushing back a different character

I don't find it surprising that the ungetc() uses you have seen all push back the character that was just read. That is certainly the primary intended use case, as reflected in the function's name. But that you haven't seen examples of other uses and can't think of any is irrelevant. The function's documentation specifies that it is the character passed as an argument that is pushed back, regardless of what the most recently read character was, or if there even was one.

Possibly this design reflects a convergence of multiple goals of C's designers:

  • memory conservation - why make every FILE in the system take an additional byte of RAM, of which there may be only a few thousand overall,* just to support a rarely-used function?

  • flexible interface - why create a system interface that can do only one specific thing when it could instead do a more general thing for little or no additional cost?


*Early C development was largely done on the PDP-11, whose minimal configuration featured a whopping 4 KB of RAM. Though I think Bell Labs' was somewhat more generously configured.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

You may use any character in the call of ungetc. It is not necessary that it must be the same as the last read character.

That is the function has a more general behavior.

More general functions have more applications.

For example if the last read character is tab character '\t' you can substitute it for space character ' ' in the input stream.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335