Character I/O
In this section, we'll examine
library functions that read and write single characters. These functions work
equally well with text streams and binary streams.
You'll notice that the functions in this section treat characters as
values of type int, not char. One reason is that the input functions indicate
an end-of-file (or error) condition by returning EOF, which is a negative integer constant.
Output
Functions
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int
putchar(int c);
putchar
writes one character to the stdout stream:
putchar(ch); /*
writes ch to stdout */
fputc and putc are more general versions of putchar that write a
character to an arbitrary stream:
fputc(ch, fp); /* writes ch to fp */
putc(ch, fp); /* writes ch to fp */
Although putc and fputc do the same thing, putc is
usually implemented as a macro (as well as a function), while fputc is
implemented only as a function, putchar itself is usually a macro defined in
the following way:
#define
putchar(c) putc((c), stdout)
It may seem odd that the library
provides both putc and fputc. But, as we saw in macros have several potential problems. The C
standard allows the putc macro to evaluate the stream argument more than once,
which fputc isn't permitted to do. Although programmers usually prefer putc,
which gives a faster program, fputc is available as an alternative.
If a write error occurs, all three functions set the
error indicator for the stream and return EOF; otherwise, they return the character that was written.
Input Functions
int fgetc(FILE *stream);
int
getc(FILE *stream);
int
getchar(void);
int ungetc(int c,
FILE *stream);
getchar
reads a character from the stdin stream:
ch =
getchar(); /* reads a character from stdin */
fgetc and
getc read a character from an arbitrary stream:
ch = fgetc(fp); /* reads a character from fp */
ch = getc(fp); /* reads a character from fp */
All three functions treat the character as an unsigned char value
(which is then converted to int type before it's returned). As a result, they
never return a negative value other than EOF.
The relationship
between getc and fgetc is similar to that between putc and fputc. getc is
usually implemented as a macro (as well as a function), while fgetc is
implemented only as a function, getchar is normally a macro as well:
#define getchar() getc(stdin)
For reading characters from a file, programmers usually prefer getc
over fgetc. Since getc is normally available in macro form, it tends to be
faster, fgetc can be used as a backup if getc isn't appropriate. (The standard
allows the getc macro to evaluate its argument more than once, which may be a
problem.)
The fgetc, getc. and getchar functions behave the same if a problem
occurs. At end-of-file. they set the stream's end-of-file indicator and return
EOF. If a read error occurs, they set the stream's error indicator and return
EOF. To differentiate between the two situations, we can call either feof or
ferror.
One of the most common uses of fgetc, getc, and getchar is to read
characters from a file, one by one, until end-of-file occurs. It's customary to
use the following while loop for that purpose:
while
((ch = getc(fp)) != EOF) {
…..
}
After reading a character from the file associated with f p and storing
it in the variable ch (which must be of type int), the while test compares ch
with EOF. If ch isn't equal to EOF, we're not at the end of the file yet, so the
body of the loop is executed. If ch is equal to EOF, the loop terminates.
Always store the return value of fgetc. getc, or getchar in an int
variable, not a char variable. Testing a char variable against EOF may give the
wrong, result.
There's one other
character input function, ungetc, which "pushes back" a character
read from a stream and clears the stream's end-of-file indicator. This
capability can be handy if we need a "loofcahead" character during
input. For instance, to read a series of digits, stopping at the first
nondigit. we could write
while (isdigit(ch = getc(fp))) {
…
}
ungetc(ch,
fp); /* pushes back last character read */
The number of characters that can be pushed back by consecutive calls
of ungetc with no intervening read operations depends on the implementation and
the type of stream involved; only the first call is guaranteed to succeed.
Calling a file-positioning function (fseek, fsetpos, or rewind) causes the
pushed- back characters to be lost.
ungetc
returns the character it was asked to push back. However, it returns EOF
if an attempt is made to push back EOF or to push back more characters
than the implementation allows.
Line I/O
We'll now turn to library functions that read and write
lines. These functions are used mostly with text streams, although it's legal
to use them with binary streams as well.
Output
Functions
int fputs(const char * restrict s, FILE * restrict stream);
int puts(const char *s);
The puts function it writes a string of characters to
stdout:
puts("Hi, there!");
/* writes to stdout */
After it writes
the characters in the string, puts always adds a new-line character.
The
gets function, which we first encountered in Section 13.3, reads a line of
input from stdin:
gets(str); /* reads a line from
stdin */
gets reads characters one by one, storing them in the array
pointed to by str, until it reads a new-line character (which it discards).
fgets
is a more general version of gets that can read from any stream, f gets is also
safer than gets, since it limits the number of characters that it will store.
Here's how we might use fgets, assuming that str is the name of a character
array:
fgets(str, sizeof(str), fp); /*
reads a line from fp */
This call will cause fgets to read characters until it
reaches the first new-line character or sizeof (str) - 1 characters have been
read, whichever happens first. If it reads the new-line character, fgets stores
it along with the other characters. (Thus, gets never stores the
new-line character, but fgets sometimes does.)
Both gets and fgets return a null pointer if a read error
occurs or they reach the end of the input stream before storing any characters.
(As usual, we can call feof or ferror to determine which situation occurred.)
Otherwise, both return their first argument, which points to the array in which
the input was stored. As you'd expect, both functions store a null character at
the end of the string.
Now
that you know about fgets, I'd
suggest using it instead of gets in most situations. With gets, there's always
the possibility of stepping outside the bounds of the receiving array, so it's
safe to use only when the string being read is guaranteed to fit into
the array. When there's no guarantee (and there usually isn't), it's much safer
to use fgets. Note that fgets will read from the standard input stream if
passed stdin as its third argument:
fgets(str, sizeof(str), stdin);
Block I/O
size_t fread(void * restrict
ptr,size_t size, size_t nmemb, FILE * restrict stream);
size_t
fwrite(const void * restrict ptr, size_t size, size_t nmemb, FILE *
restrict stream);
The fread and fwrite functions allow a program to read and
write large blocks of data in a single step, fread and fwrite are used primarily
with binary streams, although with care it's possible to use them with text
streams as well.
fwrite is
designed to copy an array from memory to a stream. The first argument in a call
of fwrite is the array's address, the second argument is the size of each array
element (in bytes), and the third argument is the number of elements to write.
The fourth argument is a file pointer, indicating where the data should be
written. To write the entire contents of the array a, for instance, we could
use the following call of fwrite:
fwrite(a, sizeof (a [0]), sizeof(a)
/ sizeof(a [0]), fp) ;
There's no rule that we have to write the entire array: we
could just as easily write any portion of it. fwrite returns the number of
elements (nor bytes) actually written. This number will be less than
the third argument if a write error occurs.
fread will
read the elements of an array from a stream, f read's arguments are similar to
fwrite's: the array's address, the size of each element (in bytes), the number
of elements to read, and a file pointer. To read the contents of a file into
the array a, we might use the following call of fread:
n = fread(a, sizeof(a [0]),
sizeof(a) / sizeof(a[0]), fp) ;
It's important to check f read's return value, which
indicates the actual number of elements (not bytes) read. This number
should equal the third argument unless the end of the input file was reached or
a read error occurred. The feof and ferror functions can be used to determine
the reason for any shortage.
fwrite is
convenient for a program that needs to store data in a file before terminating.
Later, the program (or another program, for that matter) can use fread to read
the data back into memory. Despite appearances, the data doesn't need to be in
array form; fread and fwrite work just as well with variables of all kinds.
Structures, in particular, can be read by fread or written by fwrite. To write
a structure variable s to a file, for instance, we could use the following call
of fwrite:
fwrite(&s, sizeof(s), 1, fp) ;
Be careful when using fwrite to write out structures that
contain pointer values; these values aren't guaranteed to be valid when read
back in.
No comments:
Post a Comment