12. Stdio

comp.lang.c FAQ list · Question 12.1

Q: What's wrong with this code?

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

A: For one thing, the variable to hold getchar's return value must be an int. EOF is an ``out of band'' return value from getchar: it is distinct from all possible char values which getchar can return. (On modern systems, it does not reflect any actual end-of-file character stored in a file; it is a signal that no more characters are available.) getchar's return value must be stored in a variable larger than char so that it can hold all possible char values, and EOF.

Two failure modes are possible if, as in the fragment above, getchar's return value is assigned to a char.

  1. If type char is signed, and if EOF is defined (as is usual) as -1, the character with the decimal value 255 ('\377' or '\xff' in C) will be sign-extended and will compare equal to EOF, prematurely terminating the input. [footnote]
  2. If type char is unsigned, an actual EOF value will be truncated (by having its higher-order bits discarded, probably resulting in 255 or 0xff) and will not be recognized as EOF, resulting in effectively infinite input.

The bug can go undetected for a long time, however, if chars are signed and if the input is all 7-bit characters. (Whether plain char is signed or unsigned is implementation-defined.)

References: K&R1 Sec. 1.5 p. 14
K&R2 Sec. 1.5.1 p. 16
ISO Sec., Sec. 7.9.1, Sec.
H&S Sec. 5.1.3 p. 116, Sec. 15.1, Sec. 15.6
CT&P Sec. 5.1 p. 70
PCS Sec. 11 p. 157

comp.lang.c FAQ list · Question 12.1b

Q: I have a simple little program that reads characters until EOF, but how do I actually enter that ``EOF'' value from the keyboard? I see that EOF is defined by <stdio.h> to be -1; am I supposed to enter -1?

A: If you think about it, what you enter can't be -1, because ``-1'' is two characters, and getchar is reading one character at a time. It turns out that the value of EOF as seen within your C program has essentially nothing to do with the keystroke combination you might use to signal end-of-file from the keyboard. EOF is essentially a signal to your program that no more characters will be available from that input, for whatever reason (end of a disk file, user is done typing, network stream has closed, I/O error, etc.).

Depending on your operating system, you indicate end-of-file from the keyboard using various keystroke combinations, usually either control-D or control-Z. The operating system and stdio library then arrange that your C program receive the EOF value. (Note, however, that there are various translations involved along the way. Under normal circumstances, you should not explicitly check for the control-D or control-Z value yourself, nor will you find that the <stdio.h> macro EOF is defined to be either of these values.)

comp.lang.c FAQ list · Question 12.2

Q: Why does the simple line-copying loop while(!feof(infp)) { fgets(buf, MAXLINE, infp); fputs(buf, outfp); } copy the last line twice?

A: In C, end-of-file is only indicated after an input routine has tried to read, and failed. (In other words, C's I/O is not like Pascal's.) Usually, you should just check the return value of the input routine:

	while(fgets(buf, MAXLINE, infp) != NULL)
		fputs(buf, outfp);
In virtually all cases, there's no need to use feof at all. (feof, or more likely ferror, may be useful after a stdio call has returned EOF or NULL, to distinguish between an end-of-file condition and a read error.)

References: K&R2 Sec. 7.6 p. 164
ISO Sec. 7.9.3, Sec., Sec.
H&S Sec. 15.14 p. 382

comp.lang.c FAQ list · Question 12.3

Q: I'm using fgets to read lines from a file into an array of pointers. Why do all the lines end up containing copies of the last line?

A: See question 7.4.

comp.lang.c FAQ list · Question 12.4

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

A: It's best to use an explicit fflush(stdout) whenever output should definitely be visible (and especially if the text does not end with \n). [footnote] Several mechanisms attempt to perform the fflush for you, at the ``right time,'' but they tend to apply only when stdout is an interactive terminal. (See also question 12.24.)

References: ISO Sec.

comp.lang.c FAQ list · Question 12.5

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

A: See question 19.1.

comp.lang.c FAQ list · Question 12.6

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

A: Simply double the percent sign: %% .

The reason it's tricky to print % signs with printf is that % is essentially printf's escape character. Whenever printf sees a %, it expects it to be followed by a character telling it what to do next. The two-character sequence %% is defined to print a single %.

To understand why \% can't work, remember that the backslash \ is the compiler's escape character, and controls how the compiler interprets source code characters at compile time. In this case, however, we want to control how printf interprets its format string at run-time. As far as the compiler is concerned, the escape sequence \% is undefined, and probably results in a single % character. It would be unlikely for both the \ and the % to make it through to printf, even if printf were prepared to treat the \ specially.

Additional links: further reading

See also questions 8.8 and 19.17.

References: K&R1 Sec. 7.3 p. 147
K&R2 Sec. 7.2 p. 154
ISO Sec.

comp.lang.c FAQ list · Question 12.7

Q: Why doesn't

long int n = 123456;
printf("%d\n", n);

A: Whenever you print long ints you must use the l (lower case letter ``ell'') modifier in the printf format (e.g. %ld). printf can't know the types of the arguments which you've passed to it, so you must let it know by using the correct format specifiers.

comp.lang.c FAQ list · Question 12.8

Q: I thought that ANSI function prototypes were supposed to guard against argument type mismatches.

A: See question 15.3.

comp.lang.c FAQ list · Question 12.9

Q: Someone told me it was wrong to use %lf with printf. How can printf use %f for type double, if scanf requires %lf?

A: It's true that printf's %f specifier works with both float and double arguments.[footnote] Due to the ``default argument promotions'' (which apply in variable-length argument lists [footnote] such as printf's, whether or not prototypes are in scope), values of type float are promoted to double, and printf therefore sees only doubles. (printf does accept %Lf, for long double.) See also question 15.2.

scanf, on the other hand, accepts pointers, and no such promotions apply. Storing into a float (via a pointer) is very different from storing into a double, so scanf distinguishes between %f and %lf.

Here is a table listing the argument types expected by printf and scanf for the various format specifiers:


(Strictly speaking, %lf is undefined under printf, though many systems probably accept it. To be portable, always use %f.)

See also question 12.13.

References: K&R1 Sec. 7.3 pp. 145-47, Sec. 7.4 pp. 147-50
K&R2 Sec. 7.2 pp. 153-44, Sec. 7.4 pp. 157-59
ISO Sec., Sec.
H&S Sec. 15.8 pp. 357-64, Sec. 15.11 pp. 366-78
CT&P Sec. A.1 pp. 121-33

comp.lang.c FAQ list · Question 12.9b

Q: What printf format should I use for a typedef like size_t when I don't know whether it's long or some other type?

A: Use a cast to convert the value to a known, conservatively-sized type, then use the printf format matching that type. For example, to print the size of a type, you might use

	printf("%lu", (unsigned long)sizeof(thetype));

comp.lang.c FAQ list · Question 12.10

Q: How can I implement a variable field width with printf? That is, instead of something like %8d, I want the width to be specified at run time.

A: printf("%*d", width, x) will do just what you want. The asterisk in the format specifier indicates that an int value from the argument list will be used for the field width. (Note that in the argument list, the width precedes the value to be printed.) See also question 12.15.

References: K&R1 Sec. 7.3
K&R2 Sec. 7.2
ISO Sec.
H&S Sec. 15.11.6
CT&P Sec. A.1

comp.lang.c FAQ list · Question 12.11

Q: How can I print numbers with commas separating the thousands?
What about currency formatted numbers?

A: The functions in <locale.h> begin to provide some support for these operations, but there is no standard C function for doing either task. (In Standard C, the only thing printf does in response to a custom locale setting is to change its decimal-point character.)

POSIX specifies a strfmon function for formatting monetary quantities in a locale-appropriate way, and that the apostrophe flag in a numeric printf format specifier (e.g. %'d, %'f) requests comma-separated digits.

Here is a little routine for formatting comma-separated numbers, using the locale's thousands separator, if available:

#include <locale.h>

char *commaprint(unsigned long n)
	static int comma = '\0';
	static char retbuf[30];
	char *p = &retbuf[sizeof(retbuf)-1];
	int i = 0;

	if(comma == '\0') {
		struct lconv *lcp = localeconv();
		if(lcp != NULL) {
			if(lcp->thousands_sep != NULL &&
				*lcp->thousands_sep != '\0')
				comma = *lcp->thousands_sep;
			else	comma = ',';

	*p = '\0';

	do {
		if(i%3 == 0 && i != 0)
			*--p = comma;
		*--p = '0' + n % 10;
		n /= 10;
	} while(n != 0);

	return p;
(A better implementation would use the grouping field of the lconv structure, rather than assuming groups of three digits. A safer size for retbuf might be 4*(sizeof(long)*CHAR_BIT+2)/3/3+1; see question 12.21.)

References: ISO Sec. 7.4
H&S Sec. 11.6 pp. 301-4

comp.lang.c FAQ list · Question 12.12

Q: Why doesn't the call scanf("%d", i) work?

A: The arguments you pass to scanf must always be pointers: for each value converted, scanf ``returns'' it by filling in one of the locations you've passed pointers to. (See also question 20.1.) To fix the fragment above, change it to scanf("%d", &i) .

comp.lang.c FAQ list · Question 12.12b

Q: Why does the call

char s[30];
scanf("%s", s);
work? I thought you always needed an & on each variable passed to scanf.

A: You always need a pointer; you don't necessarily need an explicit &. When you pass an array to scanf, you do not need the &, because arrays are always passed to functions as pointers, whether you use & or not. See questions 6.3 and 6.4. (If you did use an explicit &, you'd get the wrong type of pointer; see question 6.12.)

comp.lang.c FAQ list · Question 12.13

Q: Why doesn't this code:

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

A: Unlike printf, scanf uses %lf for values of type double, and %f for float. [footnote] %f tells scanf to expect a pointer-to-float, not the pointer-to-double you gave it. Either use %lf, or declare the receiving variable as a float. See also question 12.9.

comp.lang.c FAQ list · Question 12.14

Q: Why doesn't the code

short int s;
scanf("%d", &s);

A: When converting %d, scanf expects a pointer to an int. To convert to a short int, use %hd . (See also the table in question 12.9.)

comp.lang.c FAQ list · Question 12.15

Q: How can I specify a variable width in a scanf format string?

A: You can't; an asterisk in a scanf format string means to suppress assignment. You may be able to use ANSI stringizing and string concatenation to construct a constant format specifier based on a preprocessor macro containing the desired width:

#define WIDTH 3

#define Str(x) #x
#define Xstr(x) Str(x)	/* see question 11.17 */

scanf("%" Xstr(WIDTH) "d", &n);
If the width is a run-time variable, though, you'll have to build the format specifier at run time, too:
char fmt[10];
sprintf(fmt, "%%%dd", width);
scanf(fmt, &n);
(scanf formats like these are unlikely when reading from standard input, but might find some usefulness with fscanf or sscanf.)

See also questions 11.17 and 12.10.

comp.lang.c FAQ list · Question 12.16

Q: How can I read data from data files with particular formats?
How can I read ten floats without having to use a jawbreaker scanf format
like "%f %f %f %f %f %f %f %f %f %f"?
How can I read an arbitrary number of fields from a line into an array?

A: In general, there are three main ways of parsing data lines:

  1. Use fscanf or sscanf, with an appropriate format string. Despite the limitations mentioned in this section (see question 12.20), the scanf family is quite powerful. Though whitespace-separated fields are always the easiest to deal with, scanf format strings can also be used with more compact, column oriented, FORTRAN-style data. For instance, the line
    could be read with "%d%3s%f". (See also the last example in question 12.19.)
  2. Break the line into fields separated by whitespace (or some other delimiter), using strtok or the equivalent (see question 13.6), then deal with each field individually, perhaps with functions like atoi and atof. (Once the line is broken up, the code for handling the fields is much like the traditional code in main() for handling the argv array; see question 20.3.) This method is particularly useful for reading an arbitrary (i.e. not known in advance) number of fields from a line into an array.

    Here is a simple example which copies a line of up to 10 floating-point numbers (separated by whitespace) into an array:

    #define MAXARGS 10
    char line[] = "1 2.3 4.5e6 789e10";
    char *av[MAXARGS];
    int ac, i;
    double array[MAXARGS];
    ac = makeargv(line, av, MAXARGS);
    for(i = 0; i < ac; i++)
    	array[i] = atof(av[i]);
    (See question 13.6 for the definition of makeargv.)

  3. Use whatever pointer manipulations and library routines are handy to parse the line in an ad-hoc way. (The ANSI strtol and strtod functions are particularly useful for this style of parsing, because they can return a pointer indicating where they stopped reading.) This is obviously the most general way, but it's also the most difficult and error-prone: the thorniest parts of many C programs are those which use lots of tricky little pointers to pick apart strings.

When possible, design data files and input formats so that they don't require arcane manipulations, but can instead be parsed with easier techniques such as 1 and 2: dealing with the files will then be much more pleasant all around.

comp.lang.c FAQ list · Question 12.17

Q: When I read numbers from the keyboard with scanf and a "%d\n" format, like this:

	int n;
	scanf("%d\n", &n);
	printf("you typed %d\n", n);
it seems to hang until I type one extra line of input.

A: Perhaps surprisingly, \n in a scanf format string does not mean to expect a newline, but rather to read and discard characters as long as each is a whitespace character. (In fact, any whitespace character in a scanf format string means to read and discard whitespace characters. [footnote] Furthermore, formats like %d also discard leading whitespace, so you usually don't need explicit whitespace in scanf format strings at all.)

The \n in "%d\n" therefore causes scanf to read characters until it finds a non-whitespace character, and it may need to read another line before it can find that non-whitespace character. In this case, the fix is just to use "%d", without the \n (athough your program may then need to skip over the unread newline; see question 12.18a).

scanf was designed for free-format input, which is seldom what you want when reading from the keyboard. By ``free format'' we mean that scanf does not treat newlines differently from other whitespace. The format "%d %d %d" would be equally happy reading the input

	1 2 3

(By way of comparison, source code in languages like C, Pascal, and LISP is free-format, while traditional BASIC and FORTRAN are not.)

If you're insistent, scanf can be told to match a newline, using the ``scanset'' directive:

	scanf("%d%*[\n]", &n);
Scansets, though powerful, won't solve all scanf problems, however. See also question 12.20.

References: K&R2 Sec. B1.3 pp. 245-6
ISO Sec.
H&S Sec. 15.8 pp. 357-64

comp.lang.c FAQ list · Question 12.18a

Q: I'm reading a number with scanf and %d, and then a string with gets():

	int n;
	char str[80];

	printf("enter a number: ");
	scanf("%d", &n);
	printf("enter a string: ");
	printf("you typed %d and \"%s\"\n", n, str);
but the compiler seems to be skipping the call to gets()!

A: If, in response to the above program, you type the two lines

	a string
scanf will read the 42, but not the newline following it. That newline will remain on the input stream, where it will immediately satisfy gets() (which will therefore seem to read a blank line). The second line, ``a string'', will not be read at all.

If you had happened to type both the number and the string on the same line:

	42 a string
the code would have worked more or less as you expected.

As a general rule, you shouldn't try to interlace calls to scanf with calls to gets() (or any other input routines); scanf's peculiar treatment of newlines almost always leads to trouble. Either use scanf to read everything or nothing.

See also questions 12.20 and 12.23.

Additional links: longer explanation

References: ISO Sec.
H&S Sec. 15.8 pp. 357-64

comp.lang.c FAQ list · Question 12.18b

Q: I'm using scanf %c to read a Y/N response, but later input gets skipped.

A: You wanted scanf %c to read a single character, and it tried to, but when you tried to type that single character at it, before the rest of the input system would accept it, you had to hit the RETURN key, too. scanf read only the one character, but that extra newline was still sitting in an input buffer somewhere, and it's that extra newline (seemingly representing a phantom blank line) which was received by your later input call. See also questions 12.18a and 12.20.

comp.lang.c FAQ list · Question 12.19

Q: I figured I could use scanf more safely if I checked its return value to make sure that the user typed the numeric values I expect:

	int n;

	while(1) {
		printf("enter a number: ");
		if(scanf("%d", &n) == 1)
		printf("try again: ");

	printf("you typed %d\n", n);
but sometimes it seems to go into an infinite loop. [footnote] Why?

A: When scanf is attempting to convert numbers, any non-numeric characters it encounters terminate the conversion and are left on the input stream. Therefore, unless some other steps are taken, unexpected non-numeric input ``jams'' scanf again and again: scanf never gets past the bad character(s) to encounter later, valid data. If the user types a character like `x' in response to the code above, the code will loop printing ``try again'' forever, but it won't give the user a chance to try.

You may be wondering why scanf leaves unmatchable characters on the input stream. Suppose you had a compact data file containing lines consisting of a number and an alphabetic code string, without intervening whitespace, like

You might want to parse this data file with scanf, using the format string "%d%s". But if the %d conversion did not leave the unmatched character on the input stream, %s would incorrectly read "ODE" instead of "CODE". (The problem is a standard one in lexical analysis: when scanning an arbitrary-length numeric constant or alphanumeric identifier, you never know where it ends until you've read ``too far.'' This is one reason that ungetc exists.)

See also question 12.20.

References: ISO Sec.
H&S Sec. 15.8 pp. 357-64

comp.lang.c FAQ list · Question 12.20

Q: Why does everyone say not to use scanf? What should I use instead?

A: scanf has a number of problems--see questions 12.17, 12.18a, and 12.19. Also, its %s format has the same problem that gets() has (see question 12.23)--it's hard to guarantee that the receiving buffer won't overflow. [footnote]

More generally, scanf is designed for relatively structured, formatted input (its name is in fact derived from ``scan formatted''). If you pay attention, it will tell you whether it succeeded or failed, but it can tell you only approximately where it failed, and not at all how or why. You have very little opportunity to do any error recovery.

Yet interactive user input is the least structured input there is. A well-designed user interface will allow for the possibility of the user typing just about anything--not just letters or punctuation when digits were expected, but also more or fewer characters than were expected, or no characters at all (i.e. just the RETURN key), or premature EOF, or anything. It's nearly impossible to deal gracefully with all of these potential problems when using scanf; it's far easier to read entire lines (with fgets or the like), then interpret them, either using sscanf or some other techniques. (Functions like strtol, strtok, and atoi are often useful; see also questions 12.16 and 13.6.) If you do use any scanf variant, be sure to check the return value to make sure that the expected number of items were found. Also, if you use %s, be sure to guard against buffer overflow.

Note, by the way, that criticisms of scanf are not necessarily indictments of fscanf and sscanf. scanf reads from stdin, which is usually an interactive keyboard and is therefore the least constrained, leading to the most problems. When a data file has a known format, on the other hand, it may be appropriate to read it with fscanf. It's perfectly appropriate to parse strings with sscanf (as long as the return value is checked), because it's so easy to regain control, restart the scan, discard the input if it didn't match, etc.

Additional links:

References: K&R2 Sec. 7.4 p. 159

comp.lang.c FAQ list · Question 12.21

Q: How can I tell how much destination buffer space I'll need for an arbitrary sprintf call? How can I avoid overflowing the destination buffer with sprintf?

A: When the format string being used with sprintf is known and relatively simple, you can sometimes predict a buffer size in an ad-hoc way. If the format consists of one or two %s's, you can count the fixed characters in the format string yourself (or let sizeof count them for you) and add in the result of calling strlen on the string(s) to be inserted. For example, to compute the buffer size that the call

	sprintf(buf, "You typed \"%s\"", answer);
would need, you could write:
	int bufsize = 13 + strlen(answer);
	int bufsize = sizeof("You typed \"%s\"") + strlen(answer);
followed by
	char *buf = malloc(bufsize);
	if(buf != NULL)
		sprintf(buf, "You typed \"%s\"", answer);
You can conservatively estimate the size that %d will expand to with code like:
#include <limits.h>
char buf[(sizeof(int) * CHAR_BIT + 2) / 3 + 1 + 1];
sprintf(buf, "%d", n);
This code computes the number of characters required for a base-8 representation of a number; a base-10 expansion is guaranteed to take as much room or less. (The +2 takes care of truncation if the size is not a multiple of 3, and the +1+1 leaves room for a leading - and a trailing \0.) An analogous technique could of course be used for long int, and the same buffer can obviously be used with %u, %o, and %x formats as well.

When the format string is more complicated, or is not even known until run time, predicting the buffer size becomes as difficult as reimplementing sprintf, and correspondingly error-prone (and inadvisable). A last-ditch technique which is sometimes suggested is to use fprintf to print the same text to a temporary file, and then to look at fprintf's return value or the size of the file (but see question 19.12). (Using a temporary file for this application is admittedly clumsy and inelegant,[footnote] but it's the only portable solution besides writing an entire sprintf format interpreter. If your system provides one, you can use a null or ``bit bucket'' device such as /dev/null or NUL instead of a temporary file.)

If there's any chance that the buffer might not be big enough, you won't want to call sprintf without some guarantee that the buffer will not overflow and overwrite some other part of memory. If the format string is known, you can limit %s expansion by using %.Ns for some N, or %.*s (see also question 12.10).

To avoid the overflow problem, you can use a length-limited version of sprintf, namely snprintf. It is used like this:

	snprintf(buf, bufsize, "You typed \"%s\"", answer);
snprintf has been available in several stdio libraries (including GNU and 4.4bsd) for several years. It has finally been standardized in C99.

As an extra, added bonus, the C99 snprintf provides a way to predict the size required for an arbitrary sprintf call. C99's snprintf returns the number of characters it would have placed in the buffer if there were room, not just how many it did place. Furthermore, it may be called with a null pointer and a buffer size of 0 and a null pointer as the destination buffer. Therefore, the call

	nch = snprintf(NULL, 0, fmtstring, /* other arguments */ );
computes the number of characters required for the fully-formatted string. With that number (nch) in hand, you can then malloc a big-enough buffer and make a second snprintf call to fill it.

Yet another option is the (nonstandard) asprintf function, present in various C libraries including bsd's and GNU's, which formats to (and returns a pointer to) a malloc'ed buffer, like this:

char *buf;
asprintf(&buf, "%d = %s", 42, "forty-two");
/* now buf points to malloc'ed space containing formatted string */

Additional links: sample implementation of asprintf

References: C9X Sec.

comp.lang.c FAQ list · Question 12.22

Q: What's the deal on sprintf's return value? Is it an int or a char *?

A: The Standard says that it returns an int (the number of characters written, just like printf and fprintf). Once upon a time, in some C libraries, sprintf returned the char * value of its first argument, pointing to the completed result (i.e. analogous to strcpy's return value).

References: ISO Sec.
PCS Sec. 11 p. 175

comp.lang.c FAQ list · Question 12.23

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

A: Unlike fgets(), gets() cannot be told the size of the buffer it's to read into, so it cannot be prevented from overflowing that buffer if an input line is longer than expected--and Murphy's Law says that, sooner or later, a larger-than-expected input line will occur. [footnote] (It's possible to convince yourself that, for some reason or another, input lines longer than some maximum are impossible, but it's also possible to be mistaken, [footnote] and in any case it's just as easy to use fgets.)

The Standard fgets function is a vast improvement over gets(), although it's not perfect, either. (If long lines are a real possibility, their proper handling must be carefully considered.)

One other difference between fgets() and gets() is that fgets() retains the '\n', but it is straightforward to strip it out. See question 7.1 for a code fragment illustrating the replacement of gets() with fgets().

References: Rationale Sec.
H&S Sec. 15.7 p. 356

comp.lang.c FAQ list · Question 12.24

Q: I thought I'd check errno after a long string of printf calls, to see if any of them had failed:

	errno = 0;
	if(errno != 0)
		fprintf(stderr, "printf failed: %s\n", strerror(errno));
Why is it printing something strange like ``printf failed: Not a typewriter'' when I redirect the output to a file?

A: Many implementations of the stdio package adjust their behavior slightly if stdout is a terminal. To make the determination, these implementations perform some operation which happens to fail (with ENOTTY) if stdout is not a terminal. Although the output operation goes on to complete successfully, errno still contains ENOTTY. This behavior can be mildly confusing, but it is not strictly incorrect, because it is only meaningful for a program to inspect the contents of errno after an error has been reported. (More precisely, errno is only meaningful after a library function that sets errno on error has returned an error code.)

In general, it's best to detect errors by checking a function's return value. To check for any accumulated error after a long string of stdio calls, you can use ferror. See also questions 12.2 and 20.4.

References: ISO Sec. 7.1.4, Sec.
CT&P Sec. 5.4 p. 73
PCS Sec. 14 p. 254

comp.lang.c FAQ list · Question 12.25

Q: What's the difference between fgetpos/fsetpos and ftell/fseek?
What are fgetpos and fsetpos good for?

A: ftell and fseek use type long int to represent offsets (positions) in a file, and may therefore be limited to offsets which can be represented in a long int. (Type long int is not guaranteed to hold values larger than 2**31-1, limiting the maximum offset to 2 gigabytes). The newer fgetpos and fsetpos functions, on the other hand, use a special typedef, fpos_t, to represent the offsets. The type behind this typedef, if chosen appropriately, can represent arbitrarily large offsets, so fgetpos and fsetpos can be used with arbitrarily huge files. fgetpos and fsetpos also record the state associated with multibyte streams. See also question 1.4.

References: K&R2 Sec. B1.6 p. 248
ISO Sec. 7.9.1, Secs.,
H&S Sec. 15.5 p. 252

comp.lang.c FAQ list · Question 12.26a

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

A: 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. See also question 12.26b.

References: ISO Sec.
H&S Sec. 15.2

comp.lang.c FAQ list · Question 12.26b

Q: If fflush won't work, what can I use to flush input?

A: It depends on what you're trying to do. If you're trying to get rid of an unread newline or other unexpected input after calling scanf (see questions 12.18a-12.19), you really need to rewrite or replace the call to scanf (see question 12.20). Alternatively, you can consume the rest of a partially-read line with a simple code fragment like

	while((c = getchar()) != '\n' && c != EOF)
		/* discard */ ;

(You may also be able to use the curses flushinp function.)

There is no standard way to discard unread characters from a stdio input stream. Some vendors do implement fflush so that fflush(stdin) discards unread characters, although portable programs cannot depend on this. (Some versions of the stdio library implement fpurge or fabort calls which do the same thing, but these aren't standard, either.) Note, too, that flushing stdio input buffers is not necessarily sufficient: unread characters can also accumulate in other, OS-level input buffers. If you're trying to actively discard input (perhaps in anticipation of issuing an unexpected prompt to confirm a destructive action, for which an accidentally-typed ``y'' could be disastrous), you'll have to use a system-specific technique to detect the presence of typed-ahead input; see questions 19.1 and 19.2. Keep in mind that users can become frustrated if you discard input that happened to be typed too quickly.

References: ISO Sec.
H&S Sec. 15.2

comp.lang.c FAQ list · Question 12.27

Q: I wrote this routine which is supposed to open a file:

	myfopen(char *filename, FILE *fp)
		fp = fopen(filename, "r");
But when I call it like this:
		FILE *infp;
		myfopen("filename.dat", infp);
the infp variable in the caller doesn't get set properly.

A: Functions in C always receive copies of their arguments, so a function can never ``return'' a value to the caller by assigning to an argument. See question 4.8.

For this example, one fix is to change myfopen to return a FILE *:

	FILE *myfopen(char *filename)
		FILE *fp = fopen(filename, "r");
		return fp;
and call it like this:
		FILE *infp;
		infp = myfopen("filename.dat");
Alternatively, have myfopen accept a pointer to a FILE * (a pointer-to-pointer-to-FILE):
	myfopen(char *filename, FILE **fpp)
		FILE *fp = fopen(filename, "r");
		*fpp = fp;
and call it like this:
		FILE *infp;
		myfopen("filename.dat", &infp);

comp.lang.c FAQ list · Question 12.28

Q: I can't even get a simple fopen call to work! What's wrong with this call?

	FILE *fp = fopen(filename, 'r');

A: fopen's mode argument must be a string, like "r", not a character like 'r'. See also question 8.1.

comp.lang.c FAQ list · Question 12.28b

Q: How can I open files with names like ``file1'', ``file2'', ``file3'', etc., where the numeric part is controlled by a variable? Basically I want ``file%d'', like printf.

A: You want printf's close cousin sprintf, which ``prints'' to a string:

	char filename[FILENAME_MAX];
	sprintf(filename, "file%d", i);
	fp = fopen(filename, "r");

comp.lang.c FAQ list · Question 12.29

Q: fopen is failing for certain pathnames.

A: See questions 19.17 and 19.17b.

comp.lang.c FAQ list · Question 12.30

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

A: 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; there is no way to insert or delete characters in place. Finally, remember that overwriting in text mode may truncate the file at that point, and that you may have to preserve line lengths. See also question 19.14.

References: ISO Sec.

comp.lang.c FAQ list · Question 12.31

Q: How can I insert or delete a line (or record) in the middle of a file?

A: See question 19.14.

comp.lang.c FAQ list · Question 12.32

Q: How can I recover the file name given an open stream?

A: See question 19.15.

comp.lang.c FAQ list · Question 12.33

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

A: Use freopen. If you're calling a function f() which writes to stdout, and you want to send its output to a file, and you don't have the option of rewriting f, you can use a sequence like:

	freopen(file, "w", stdout);
See, however, question 12.34.

References: ISO Sec.
H&S Sec. 15.2

comp.lang.c FAQ list · Question 12.34

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

A: There isn't a good way. If you need to switch back, the best solution is not to have used 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. For example, declare a global

	FILE *ofp;
and replace all calls to printf( ... ) with fprintf(ofp, ... ). (Obviously, you'll have to check for calls to putchar and puts, too.) Then you can set ofp to stdout or to anything else.

You might wonder if you could skip freopen entirely, and do something like

	FILE *savestdout = stdout;
	stdout = fopen(file, "w");	/* WRONG */
leaving yourself able to restore stdout later by doing
	stdout = savestdout;		/* WRONG */
but code like this is not likely to work, because stdout (and stdin and stderr) are typically constants which cannot be reassigned (which is why freopen exists in the first place).

It may be possible, in a nonportable way, to save away information about a stream before calling freopen to open some file in its place, such that the original stream can later be restored. The most straightforward and reliable way is to manipulate the underlying file descriptors using a system-specific call such as dup or dup2, if available (example). Another is to copy or inspect the contents of the FILE structure, but this is exceedingly nonportable and unreliable.

Under some systems, you might be able to reopen a special device file (such as /dev/fd/1 under modern versions of Unix) which is still attached to (for example) the original standard output. You can, under some systems, explicitly re-open the controlling terminal (see question 12.36), but this isn't necessarily what you want, since the original input or output (i.e. what stdin or stdout had been before you called freopen) could have been redirected from the command line.

All of this pertains to stdio redirection initially performed by freopen, affecting the I/O calls within the same program that called freopen. If what you're trying to do is capture the result of a subprogram execution, freopen probably won't work anyway; see question 19.30 instead.

Additional links: examples

comp.lang.c FAQ list · Question 12.35

Q: How can I tell if standard input or output is redirected (i.e. whether ``<'' or ``>'' was used on the invocation command line)?

A: You can't tell directly, but you can usually look at a few other things to make whatever decision you need to. If you want your program to take input from stdin when not given any input files, you can do so if argv doesn't mention any input files (see question 20.3), or perhaps if you're given a placeholder like ``-'' instead of a filename. If you want to suppress prompts if input is not coming from an interactive terminal, on some systems (e.g. Unix, and usually MS-DOS) you can use isatty(0) or isatty(fileno(stdin)) to make the determination.

comp.lang.c FAQ list · Question 12.36

Q: I'm trying to write a program like ``more.'' How can I get back to the interactive keyboard if stdin is redirected?

A: There is no portable way of doing this. Under Unix, you can open the special file /dev/tty. Under MS-DOS, you can try opening the ``file'' CON, or use routines or BIOS calls such as getch which may go to the keyboard whether or not input is redirected.

comp.lang.c FAQ list · Question 12.36b

Q: How can I arrange to have output go two places at once, e.g. to the screen and to a file?

A: You can't do this directly, but you could write your own printf variant which printed everything twice. Here is a sample logprintf function which prints to both stdout and a preopened log file:

#include <stdio.h>
#include <stdarg.h>

extern FILE *logfp;

void logprintf(char *fmt, ...)
	va_list argp;
	va_start(argp, fmt);
	vfprintf(stdout, fmt, argp);
	va_start(argp, fmt);
	vfprintf(logfp, fmt, argp);
Now, whenever you call logprintf (which you can call with format strings just like printf), it prints both to stdout and to logfp, which you have presumably opened to your desired log file. Another way to arrange this would be
void f2printf(FILE *fp1, FILE *fp2, char *fmt, ...)
	va_list argp;
	va_start(argp, fmt); vfprintf(fp1, fmt, argp); va_end(argp);
	va_start(argp, fmt); vfprintf(fp2, fmt, argp); va_end(argp);
where f2printf is just like fprintf except that you give it two file pointers (e.g. stdout and logfp) and it prints to both of them.

Both of these techniques obviously require you to use explicit calls to logprintf or f2printf. There is no known way in Standard C to arrange implicitly (i.e. via some call analogous to freopen) that one stream, which you print to once with a normal call like fprintf, print to two places at once. [footnote]

See also question 15.5.

comp.lang.c FAQ list · Question 12.37

Q: I want to read and write numbers between files and memory in a byte-at-a-time way, not as formatted characters the way fprintf and fscanf do. How can I do this?

A: What you're trying to do is usually called ``binary'' I/O. First, make sure that you are calling fopen with the "b" modifier ("rb", "wb", etc.; see question 12.38). Then, use the & and sizeof operators to get a handle on the sequences of bytes you are trying to transfer. Usually, the fread and fwrite functions are what you want to use; see question 2.11 for an example.

Note, though, that fread and fwrite do not necessarily imply binary I/O. If you've opened a file in binary mode, you can use any I/O calls on it (see for example the examples in question 12.42); if you've opened it in text mode, you can use fread or fwrite if they're convenient.

Finally, note that binary data files are not very portable; see question 20.5.

See also question 12.40.

comp.lang.c FAQ list · Question 12.38

Q: How can I read a binary data file properly? I'm occasionally seeing 0x0a and 0x0d values getting garbled, and I seem to hit EOF prematurely if the data contains the value 0x1a.

A: When you're reading a binary data file, you should specify "rb" mode when calling fopen, to make sure that text file translations do not occur. Similarly, when writing binary data files, use "wb". (Under operating systems such as Unix which don't distinguish between text and binary files, "b" may not be required, but is harmless.)

Note that the text/binary distinction is made when you open the file: once a file is open, it doesn't matter which I/O calls you use on it. See also questions 12.37, 12.40, 12.42, and 20.5.

References: ISO Sec.
H&S Sec. 15.2.1 p. 348

comp.lang.c FAQ list · Question 12.39

Q: I'm writing a ``filter'' for binary files, but stdin and stdout are preopened as text streams. How can I change their mode to binary?

A: There is no standard way to do this. On Unix-like systems, there is no text/binary distinction, so there is no need to change the mode. Some MS-DOS compilers supply a setmode call. Otherwise, you're on your own.

comp.lang.c FAQ list · Question 12.40

Q: What's the difference between text and binary I/O?

A: In text mode, a file is assumed to consist of lines of printable characters (perhaps including tabs). The routines in the stdio library (getc, putc, and all the rest) translate between the underlying system's end-of-line representation and the single \n used in C programs. C programs which simply read and write text therefore don't have to worry about the underlying system's newline conventions: when a C program writes a '\n', the stdio library writes the appropriate end-of-line indication, and when the stdio library detects an end-of-line while reading, it returns a single '\n' to the calling program. [footnote]

In binary mode, on the other hand, bytes are read and written between the program and the file without any interpretation. (On MS-DOS systems, binary mode also turns off testing for control-Z as an in-band end-of-file character.)

Text mode translations also affect the apparent size of a file as it's read. Because the characters read from and written to a file in text mode do not necessarily match the characters stored in the file exactly, the size of the file on disk may not always match the number of characters which can be read from it. Furthermore, for analogous reasons, the fseek and ftell functions do not necessarily deal in pure byte offsets from the beginning of the file. (Strictly speaking, in text mode, the offset values used by fseek and ftell should not be interpreted at all: a value returned by ftell should only be used as a later argument to fseek, and only values returned by ftell should be used as arguments to fseek.)

In binary mode, fseek and ftell do use pure byte offsets. However, some systems may have to append a number of null bytes at the end of a binary file to pad it out to a full record.

See also questions 12.37 and 19.12.

References: ISO Sec. 7.9.2
Rationale Sec. 4.9.2
H&S Sec. 15 p. 344, Sec. 15.2.1 p. 348

comp.lang.c FAQ list · Question 12.41

Q: How can I read/write structures from/to data files?

A: See question 2.11.

comp.lang.c FAQ list · Question 12.42

Q: How can I write code to conform to these old, binary data file formats?

A: It's hard, because of word size and byte order differences, floating-point formats, and structure padding. To get the control you need over these particulars, you may have to read and write things a byte at a time, shuffling and rearranging as you go. (This isn't always as bad as it sounds, and gives you both portability of your code and complete control.)

For example, to read a data structure consisting of a character, a 32-bit integer, and a 16-bit integer, from the stream fp, into the C structure

struct mystruct {
	char c;
	long int i32;
	int i16;
} s;
you might use code like this:
	s.c = getc(fp);

	s.i32 = (long)getc(fp) << 24;
	s.i32 |= (long)getc(fp) << 16;
	s.i32 |= (unsigned)(getc(fp) << 8);
	s.i32 |= getc(fp);

	s.i16 = getc(fp) << 8;
	s.i16 |= getc(fp);
This code assumes that getc reads 8-bit characters, and that the data is stored most significant byte first (``big endian''). The casts to (long) ensure that the 16- and 24-bit shifts operate on long values (see question 3.14), and the cast to (unsigned) guards against sign extension. (In general, it's safer to use all unsigned types when writing code like this, but see question 3.19.)

The corresponding code to write the structure might look like:

	putc(s.c, fp);

	putc((unsigned)((s.i32 >> 24) & 0xff), fp);
	putc((unsigned)((s.i32 >> 16) & 0xff), fp);
	putc((unsigned)((s.i32 >> 8) & 0xff), fp);
	putc((unsigned)(s.i32 & 0xff), fp);

	putc((s.i16 >> 8) & 0xff, fp);
	putc(s.i16 & 0xff, fp);

See also questions 2.12, 12.38, 16.7, and 20.5.

comp.lang.c FAQ list · Question 12.43

Q: I'm reading strings typed by the user into an array, and then printing them out later. When the user types a sequence like \n, why isn't it being handled properly?

A: See question 8.8.

Read sequentially: prev next up

about this FAQ list   about eskimo   search   feedback   copyright

Hosted by Eskimo North