[prev] [up] [overview] [next]

Section 11. Stdio

11.1: What's wrong with this code:

	char c;
	while((c = getchar()) != EOF)...

For one thing, the variable to hold getchar's return value must be an int.  getchar can return all possible character values, as well as EOF By passing getchar's return value through a char, either a normal character might be misinterpreted as EOF, or the EOF might be altered (particularly if type char is unsigned) and so never seen.

References: CT&P Sec. 5.1 p. 70.

11.2: How can I print a'%' character in a printf format string?  I tried \%, but it didn't work.

Simply double the percent sign: %% .

References: K&R I Sec. 7.3 p. 147; K&R II Sec. 7.2 p. 154; ANSI Sec. 4.9.6.1 .

11.3: Why doesn't the code scanf("%d", i); work? scanf needs pointers to the variables it is to fill in; you must call scanf("%d", &i);

11.4: Why doesn't this code:

	double d;
	scanf("%f", &d);

work?

scanf uses %lf for values of type double and %f for float. (Note the discrepancy with printf , which uses %f for both double and float due to C's default argument promotion rules.)

11.5: Why won't the code

	while(!feof(infp)) {
		fgets(buf, MAXLINE, infp);
		fputs(buf, outfp);
	}

work?

C's I/O is not like Pascal's.  EOF is only indicated after an input routine has tried to read, and has reached end-of-file. Usually, you should just check the return value of the input routine (fgets in this case); often, you don't need to use feof() at all.

11.6: Why does everyone say not to use gets()?

It cannot be told the size of the buffer it's to read into, so it cannot be prevented from overflowing that buffer.  See question 3.1 for a code fragment illustrating the replacement of gets() with fgets().

11.7: Why does errno contain ENOTTY after a call to printf?

Many implementations of the stdio package adjust their behavior slightly if stdout is a terminal.  To make the determination, these implementations perform an operation which fails (with ENOTTY) if stdout is not a terminal.  Although the output operation goes on to complete successfully, errno still contains ENOTTY.

References: CT&P Sec. 5.4 p. 73.

11.8: My program's prompts and intermediate output don't always show up on the screen, especially when I pipe the output through another program.

It is best to use an explicit fflush(stdout) whenever output should definitely be visible.  Several mechanisms attempt to perform the fflush for you, at the "right time," but they tend to apply only when stdout is a terminal.  (See question 11.7.)

11.9: When I read from the keyboard with scanf, it seems to hang until I type one extra line of input.

scanf was designed for free-format input, which is seldom what you want when reading from the keyboard.  In particular, "\n" in a format string does not mean to expect a newline, but rather to read and discard characters as long as each is a whitespace character.

A related problem is that unexpected non-numeric input can cause scanf to "jam."  Because of these problems, it is usually better to use fgets to read a whole line, and then use sscanf or other string functions to pick apart the line buffer.  If you do use sscanf, don't forget to check the return value to make sure that the expected number of items were found.

11.10: I'm trying to update a file in place, by using fopen mode "r+", then reading a certain string, and finally writing back a modified string, but it's not working.

Be sure to call fseek before you write, both to seek back to the beginning of the string you're trying to overwrite, and because an fseek or fflush is always required between reading and writing in the read/write "+" modes.  Also, remember that you can only overwrite characters with the same number of replacement characters; see also question 17.4.

References: ANSI Sec. 4.9.5.3 p. 131.

11.11: How can I read one character at a time, without waiting for the RETURN key?

See question 16.1.

11.12: How can I flush pending input so that a user's typeahead isn't read at the next prompt?  Will fflush(stdin) work?

fflush is defined only for output streams.  Since its definition of "flush" is to complete the writing of buffered characters (not to discard them), discarding unread input would not be an analogous meaning for fflush on input streams.  There is no standard way to discard unread characters from a stdio input buffer, nor would such a way be sufficient; unread characters can also accumulate in other, OS-level input buffers.

11.13: How can I redirect stdin or stdout to a file from within a program?

Use freopen.

11.14: Once I've used freopen, how can I get the original stdout (or stdin) back?

If you need to switch back and forth, the best all-around solution is not to use freopen in the first place.  Try using your own explicit output (or input) stream variable, which you can reassign at will, while leaving the original stdout (or stdin) undisturbed.

11.15: How can I recover the file name given an open file descriptor?

This problem is, in general, insoluble.  Under Unix, for instance, a scan of the entire disk, (perhaps requiring special permissions) would theoretically be required, and would fail if the file descriptor was a pipe or referred to a deleted file (and could give a misleading answer for a file with multiple links).  It is best to remember the names of files yourself when you open them (perhaps with a wrapper function around fopen).


[prev] [up] [overview] [next]