Standard IO

I l @ ve RuBoard

Standard I/O

The standard I/O package has two advantages, besides portability, over low-level I/O. First, it has many specialized functions that simplify handling different I/O problems. For instance, printf() converts various forms of data to string output suitable for terminals. Second, input and output are buffered . That is, information is transferred in large chunks (typically 512 bytes at a time or more) instead of a byte at a time. When a program reads a file, for example, a chunk of data is copied to a buffer ”an intermediate storage area. This buffering greatly increases the data transfer rate. The program can then examine individual bytes in the buffer. The buffering is handled behind the scenes, so you have the illusion of character-by-character access. (You can also buffer low-level I/O, but you have to do much of the work yourself.) Listing 12.1 shows how to use standard I/O to read a file and count the number of characters in the file. We'll discuss the features of Listing 12.1 in the next several sections. (Windows users might have to run the program in an MS-DOS window after compiling. Macintosh users should use console.h and the ccommand() function as described in Chapter 11, "Characters Strings and String Functions," and in the Think C documentation.)

Listing 12.1 The count.c program.
 /* count.c -- using standard I/O */ #include <stdio.h> #include <stdlib.h> /* ANSI C exit() prototype               */ int main(int argc, char *argv[]) {     int ch;         /* place to store each character as read */     FILE *fp;       /* "file pointer"                        */     long count = 0;     if (argc != 2)     {         printf("Usage: %s filename\n", argv[0]);         exit(1);     }     if ((fp = fopen(argv[1], "r")) == NULL)     {         printf("Can't open %s\", argv[1]);         exit(1);     }     while ((ch = getc(fp)) != EOF)     {        putc(ch,stdout);        count++;     }     fclose(fp);     printf("File %s has %ld characters\n", argv[1], count);     return 0; } 

Checking for Command-Line Arguments

First, the program in Listing 12.1 checks the value of argc to see if there is a command-line argument. If there isn't, the program prints a usage message and exits. The string argv[0] is the name of the program. Using argv[0] instead of the program name explicitly causes the error message to change automatically if you change the name of the executable file. This feature is also handy in environments like UNIX that permit multiple names for a single file. But beware ”some operating systems, such as pre-MS-DOS 3.0, don't recognize argv[0] , so this usage is not completely portable.

The exit() function causes the program to terminate, closing any open files. The argument to exit() is passed on to some operating systems, including UNIX and PC DOS, where it can be used by other programs. The usual convention is to pass a value of for programs that terminate normally and to pass nonzero values for abnormal termination. Different exit values can be used to distinguish between different causes of failure, and this is the usual practice in UNIX and DOS programming. However, not all operating systems recognize the same range of possible return values. Therefore, the ANSI C standard mandates a rather restricted minimum range. In particular, the standard requires that the value or the macro EXIT_SUCCESS be used to indicate successful termination, and the macro EXIT_FAILURE be used to indicate unsuccessful termination. These macros, along with the exit() prototype, are found in the stdlib.h header file. This book will follow the common practice of using integer exit values, but for maximum portability, use EXIT_SUCCESS and EXIT_FAILURE .

Under ANSI C, using return in the initial call to main() has the same effect as calling exit() . Therefore, the following statement

 return 0; 
which you've been using all along, is equivalent in effect to this statement:
 exit(0); 

Note, however, the qualifying phrase "the initial call." If you make main() into a recursive program, exit() still terminates the program, but return passes control to the previous level of recursion until the original level is reached. Then return terminates the program. Another difference between return and exit() is that exit() terminates the program even if called in a function other than main() .

The fopen() Function

Next, the program uses fopen() to open the file. This function is declared in stdio.h . Its first argument is the name of the file to be opened; more exactly, it is the address of a string containing that name. The second argument is a string identifying the mode in which the file is to be opened. The C library provides for several possibilities, as shown in Table 12.1.

Table  12.1. Mode strings for fopen() .
Mode String Meaning
"r" Open a text file for reading
"w" Open a text file for writing truncating an existing file to zero length, or creating the file if it does not exist
"a" Open a text file for writing, appending to the end of an existing file, or creating the file if it does not exist
"r+" Open a text file for update, that is, for both reading and writing
"w+" Open a text file for update (reading and writing), first truncating the file to zero length if it exists or creating the file if it does not exist
"a+" Open a text file for update (reading and writing), appending to the end of an existing file, or creating the file if it does not yet exist; the whole file can be read, but writing can only be appended
"rb", "wb", "ab", "ab+", "a+b", "wb+", "w+b", "ab+", "a+b" Like the preceding modes, except using binary mode instead of text mode mode

For systems like UNIX, which have just one file type, the modes with the b are equivalent to the corresponding modes lacking the b .

Caution

If you use any of the "w" modes for an existing file, the file contents are truncated so that your program can start with a clean slate.


After your program successfully opens a file, fopen() returns a file pointer , which the other I/O functions can then use to specify the file. The file pointer, fp in this example, is of type pointer-to- FILE ; FILE is a derived type defined in stdio.h . The pointer fp doesn't point to the actual file. Instead, it points to a data package containing information about the file, including information about the buffer used for the file's I/O. Because the I/O functions in the standard library use a buffer, they need to know where the buffer is. They also need to know how full the buffer is and which file is being used. This enables the functions to refill or empty the buffer when necessary. The data package pointed to by fp has all that information. (This data package is an example of a C structure, a topic we discuss in Chapter 14, "Structures and Other Data Forms." )

The fopen() function returns the null pointer (also defined in stdio.h ) if it cannot open the file. The program exits if fp is NULL . The fopen() function can fail because the disk is full, because the name is illegal, because access is restricted, or because of a hardware problem, to name just a few reasons, so check for trouble; a little error-trapping can go a long way.

The getc() and putc() Functions

The two functions getc() and putc() work very much like getchar () and putchar () . The difference is that you must tell these newcomers which file to use. So the following old standby means get a character from the standard input:

 ch = getchar(); 

However, this statement means get a character from the file identified by fp :

 ch = getc(fp); 

Similarly, this statements means put the character ch into the file identified by the FILE pointer fpout :

 putc(ch, fpout); 

In the putc() argument list, the character comes first, then the file pointer.

Listing 12.1 uses stdout for the second argument of putc() . It is defined in stdio.h as being the file pointer associated with the standard output, so putc(ch,stdout) is the same as putchar(ch) . Indeed, the latter function is normally defined as being the former. Similarly, getchar() is defined as being getc() using the standard input.

The fclose() Function

The fclose(fp) closes the file identified by fp , flushing buffers as needed. For a program less casual than this one, you would check to see whether the file had been closed successfully. The function fclose() returns a value of if successful, and EOF if not.

 if (fclose(fp) != 0)    printf("Error in closing file %s\n", argv[1]); 

The fclose() function can fail if, for example, the disk is full, the diskette has been removed, or there has been an I/O error.

Standard Files

The stdio.h file associates three file pointers with the three standard files automatically opened by C programs.

Standard File File Pointer Normally
Standard input stdin Your keyboard
Standard output stdout Your screen
Standard error stderr Your screen

These pointers are all type pointer-to- FILE , so they can be used as arguments to the standard I/O functions, just as fp was in the example. Let's move on to an example that creates a new file and writes to it.

I l @ ve RuBoard


C++ Primer Plus
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2000
Pages: 314
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net