Node:ungetc, Previous:putc and fputc, Up:Single-character input and output


Every time a character is read from a stream by a function like getc, the file position indicator advances by 1. It is possible to reverse the motion of the file position indicator with the function ungetc, which steps the file position indicator back by one byte within the file and reverses the effect of the last character read operation. (This is called unreading the character or pushing it back onto the stream.)

The intended purpose is to leave the indicator in the correct file position when other functions have moved too far ahead in the stream. Programs can therefore peek ahead, or get a glimpse of the input they will read next, then reset the file position with ungetc.

On GNU systems, you cannot call ungetc twice in a row without reading at least one character in between; in other words, GNU only supports one character of pushback.

Pushing back characters does not change the file being accessed at all; ungetc only affects the stream buffer, not the file. If fseek, rewind, or some other file positioning function is called, any character due to be pushed back by ungetc is discarded.

Unreading a character on a stream that is at end-of-file resets the end-of-file indicator for the stream, because there is once again a character available to be read. However, if the character pushed back onto the stream is EOF, ungetc does nothing and just returns EOF.

Here is a code example that reads all the whitespace at the beginning of a file with getc, then backs up one byte to the first non-whitespace character, and reads all following characters up to a newline character with the getline function. (See getline, for more information on that function.)

#include <stdio.h>

int main()
  int in_char;
  FILE *my_stream;
  char *my_string = NULL;
  size_t nchars = 0;

  my_stream = fopen ("snazzyjazz.txt", "w");
  fprintf (my_stream, "          Here's some non-whitespace.\n");

  /* Close stream; skip error-checking for brevity of example */
  fclose (my_stream);

  my_stream = fopen ("snazzyjazz.txt", "r");

  /* Skip all whitespace in stream */
    in_char = getc (my_stream);
  while (isspace (in_char));

  /* Back up to first non-whitespace character */
  ungetc (in_char, my_stream);

  getline (&my_string, &nchars, my_stream);

  /* Close stream; skip error-checking for brevity of example */
  fclose (my_stream);

  printf ("String read:\n");
  printf ("%s", my_string);

  return 0;

The code example will skip all initial whitespace in the file snazzyjazz.txt, and display the following text on standard output:

String read:
Here's some non-whitespace.