Formatted
I/O
In this
section, we'll examine library functions that use format strings to control
reading and writing. These functions, which include our old friends printf and
scanf, have the ability to convert data from character form to numeric form during
input and from numeric form to character form during output. None of the other
I/O functions can do such conversions.
The ...printf Functions
int fprintf(FILE *
restrict stream,const char *
restrict format,…);
int printf(const char *
restrict format, …);
The
fprintf and printf functions write a variable number of data items to an output
stream, using a format string to control the appearance of the output. The
prototypes for both functions end with the ... symbol (an ellipsis),
which indicates a variable number of additional arguments. Both functions
return the number of characters written; a negative return value indicates that
an error occurred.
The only
difference between printf and fprintf is that printf always writes to stdout
(the standard output stream), whereas fprintf writes to the stream indicated by
its first argument:
printf("Total: %d\n", total); /* writes to stdout
*/
fprintf(fp,
"Total: %d\n", total); /* writes to fp */
A call of printf is equivalent to a call of fprintf with
stdout as the first argument.
Don't
think of fprintf as merely a function that writes data to disk files, though.
Like many functions in , fprintf works fine with any output
stream. In fact, one of the most common uses of fprintf writing error messages
to stderr. the standard error stream has nothing to do with disk files. Here's
what such a call might look like:
fprintf(stderr, "Error: data
file can't be opened.\n");
Writing the message to stderr guarantees that it will appear
on the screen even if the user redirects stdout.
There
are two other functions in that can write formatted output to
a stream. These functions, named vfprintf and vprintf. are fairly obscure. Both
rely on the va list type, which is declared in , so they're
discussed along with that header.
...printf
Conversion Specifications
Both
printf and fprintf require a format string containing ordinary characters
and/or conversion specifications. Ordinary characters are printed as is; conversion
specifications describe how the remaining arguments are to be converted to
character form for display. We'll now review what we know about conversion
specifications and fill in the remaining gaps.
A ...printf conversion specification
consists of the % character, followed by as many as five distinct items:
Flag
|
Meaning
|
-
Left-justify within field. (The default is
right justification.)
|
|
+
|
Numbers produced by signed
conversions always begin with + or -. (Normally, only negative numbers are
preceded by a sign.)
|
space
|
Nonnegative numbers produced by
signed conversions are preceded by a space. (The + flag overrides the
space flag.)
|
#
|
Octal numbers begin with 0.
nonzero hexadecimal numbers with Ox or OX. Floating-point numbers always have
a decimal point Trailing zeros aren't removed from numbers printed with the g
or G conversions.
|
0
(zero)
|
Numbers are padded with leading
zeros up to the Held width. The 0 flag is ignored if the conversion is d. i,
o. u, x, or X and a precision is specified. (The - flag overrides the 0
flag.)
|
The ...scanf Functions
int fscanf(FILE * restrict
stream,const char * restrict format, ...);
int scanf(const char * restrict format,
...);
fscanf
and scanf read data items from an input stream, using a format string to
indicate the layout of the input. After the format string, any number of
pointers each pointing to an object follow as additional arguments. Input items
are converted (according to conversion specifications in the format string)
and stored in these objects.
scanf
always reads from stdin (the standard input stream), whereas fscanf reads from
the stream indicated by its first argument:
scanf ("%d%d", &i, Uj ) ; /*
reads from stdin */
fscanf(fp,
"%d%d", &i, &j); /* reads from fp */
A call of scanf is equivalent to a call of fscanf with stdin as the
first argument.
The
...scanf functions return prematurely if an input failure occurs (no
more input characters could be read) or if a matching failure occurs
(the input characters didn't match the format string). (In C99. an input
failure can also occur because of an encoding error, which means that an
attempt was made to read a multibyte character, but the input characters didn't
correspond to any valid multi- byte character.) Both functions return the
number of data items that were read and assigned to objects: they return EOF
if an input failure occurs before any data items can be read.
Loops that test
scanf's return value are common in C programs. The following loop, for
example, reads a series of integers one by one. stopping at the first sign of
trouble:
while (scanf("%d",
&i) == 1) {….
}
...scanf Format
Strings
Calls of
the ...scanf functions resemble those of the ...printf functions. That
similarity can be misleading, however; the ...scanf functions work quite differently
from the ...printf functions. It pays to think of scanf and fscanf as
"pattern-matching" functions. The format string represents a pattern
that a ...scanf function attempts to match as it reads input. If the input
doesn't match the format string, the function returns as soon as it detects the
mismatch; the input character that didn't match is "pushed back" to
be read in the future. A ...scanf format string may contain three things:
Conversion specifications. Conversion specifications in a ...scanf
format string resemble those in a ...printf format string. Most conversion
specifications skip white-space characters at the beginning of an input item
(the exceptions are % [. %c. and %n). Conversion specifications never skip
trailing white- space characters, however. If the input contains •123°”, the %d
conversion specification consumes • 1, 2, and 3, but leaves o unread. (I'm
using • to represent the space character and ° to represent the new-line
character.)
White-space characters. One or more consecutive white-space characters
in a ...scanf format string match zero or more white-space characters in the
input stream.
Non-white-space characters. A non-white-space character other than %
matches the same character in the input stream.
For example, the format string
"ISBN %d-%d-%ld-%d" specifies that the input will consist of: the
letters ISBN
possibly some white-space characters
an integer the - character
an integer (possibly preceded by
white-space characters) the - character
a long integer (possibly preceded by
white-space characters) the - character
an integer (possibly preceded by
white-space characters) ...scanf Conversion Specifications
Conversion specifications for
...scanf functions are actually a little simpler than those for ...printf functions. A ...scanf
conversion specification consists of the character % followed by the items
listed below (in the order shown).
*
(optional). The presence of * signifies
assignment suppression: an input item is read but not assigned to an
object. Items matched using * aren't included in the count that ...scanf
returns.
Maximum field width (optional). The maximum field width limits the number of
characters in an input item; conversion of the item ends if this number is
reached. White-space characters skipped at the beginning of a conversion don't
count.
Length
modifier (optional). The presence of a
length modifier indicates that the object in which the input item will be
stored has a type that's longer or shorter than is normal for a particular
conversion specification.
Detecting
End-of-File and Error Conditions
void clearerr(FILE *stream); int
feof(FILE *stream);
int f error (FILE *stream);
If
we ask a ...scanf function to read and store n data items, we expect its return
value to be n. If the return value is less than n, something went
wrong. There are three possibilities:
End-of-file. The function
encountered end-of-file before matching the format string completely.
Read error. The function was unable to read characters from
the stream.
Matching failure. A data item was in the wrong format. For
example, the function might have encountered a letter while searching for the
first digit of an integer.
But how can we tell which kind of failure occurred? In many
cases, it doesn't matter; something went wrong, and we've got to abandon the
program. There may be times, however, when we'll need to pinpoint the reason
for the failure.
Every
stream has two indicators associated with it: an error indicator and an end-of-file
indicator. These indicators are cleared when the stream is opened. Not
surprisingly, encountering end-of-file sets the end-of-file indicator, and a
read error sets the error indicator. (The error indicator is also set when a
write error occurs on an output stream.) A matching failure doesn't change
either indicator.
Once the
error or end-of-file indicator is set, it remains in that state until it's
explicitly cleared, perhaps by a call of the clearerr function, clearerr clears
both the end-of-file and error indicators:
clearerr(fp);
/+ clears eof and error indicators for fp */
clearerr
isn't needed often, since some of the other library functions clear one or both
indicators as a side effect.
We can
call the f eof and ferror functions to test a stream's indicators to determine
why a prior operation on the stream failed. The call feof (fp) returns a
nonzero value if the end-of-file indicator is set for the stream associated
with f p. The call ferror (fp) returns a nonzero value if the error indicator
is set. Both functions return zero otherwise.
When
scanf returns a smaller-than-expected value, we can use feof and ferror to
determine the reason. If feof returns a nonzero value, we've reached the end of
the input file. If ferror returns a nonzero value, a read error occurred during
input. If neither returns a nonzero value, a matching failure must have occurred.
Regardless of what the problem was, the return value of scanf tells us how many
data items were read before the problem occurred.
No comments:
Post a Comment