File IO: fprintf() , fscanf() , fgets() , and fputs()

I l @ ve RuBoard

File I/O: fprintf() , fscanf() , fgets() , and fputs()

For each of the I/O functions in the preceding chapters, there is a similar file I/O function. The main distinction is that you need to use a FILE pointer to tell the new functions which file to work with. Like getc() and putc() , these functions require that you identify a file by using a pointer-to- FILE such as stdout or that you use the return value of fopen() .

The fprintf() and fscanf() Functions

The file I/O functions fprintf() and fscanf() work just like printf() and scanf() , except that they require an additional first argument to identify the proper file. You've already used fprintf() . Listing 12.3 illustrates both of these file I/O functions along with the rewind() function.

Listing 12.3 The addaword.c program.
 /* addaword.c -- uses fprintf(), fscanf(), and rewind() */ #include <stdio.h> #include <stdlib.h> #define MAX 40 int main(void) {      FILE *fp;      char words[MAX];      if ((fp = fopen("wordy", "a+")) == NULL)      {           fprintf(stdin,"Can't open \"words\" file.\n");           exit(1);      }      puts("Enter words to add to the file; press the Enter");      puts("key at the beginning of a line to terminate.");      while (gets(words) != NULL  && words[0] != ' 
  /* addaword.c -- uses fprintf(), fscanf(), and rewind() */ #include <stdio.h> #include <stdlib.h> #define MAX 40 int main(void) { FILE *fp; char words[MAX]; if ((fp = fopen("wordy", "a+")) == NULL) { fprintf(stdin,"Can't open \"words\" file.\n"); exit(1); } puts("Enter words to add to the file; press the Enter"); puts("key at the beginning of a line to terminate."); while (gets(words) != NULL && words[0] != '\0') fprintf(fp, "%s", words); puts("File contents:"); rewind(fp); /* go back to beginning of file */ while (fscanf(fp,"%s",words) == 1) puts(words); if (fclose(fp) != 0) fprintf(stderr,"Error closing file\n"); return 0; }  
') fprintf(fp, "%s", words); puts("File contents:"); rewind(fp); /* go back to beginning of file */ while (fscanf(fp,"%s",words) == 1) puts(words); if (fclose(fp) != 0) fprintf(stderr,"Error closing file\n"); return 0; }

This program enables you to add words to a file. By using the "a+" mode, the program can both read and write in the file. The first time the program is used, it creates the words file and enables you to place words in it. When you use the program subsequently, it enables you to add (append) words to the previous contents. The append mode only enables you to add material to the end of the file, but the "a+" mode does enable you to read the whole file. The rewind() command takes the program to the file beginning so that the final while loop can print the file contents. Note that rewind() takes a file pointer argument.

If you enter an empty line, gets() places a null character in the first element of the array. Use that fact to terminate the loop.

Here's a sample run from a DOS environment:

 C>addaword Enter words to add to the file; press the Enter key at the beginning of a line to terminate.  The fabulous programmer[enter] [enter]  File contents: The fabulous programmer C>addaword Enter words to add to the file; press the Enter key at the beginning of a line to terminate.  enchanted the[enter] large[enter] [enter]  File contents: The fabulous programmer enchanted the large 

As you can see, fprintf() and fscanf() work like printf() and scanf() . Unlike putc() , the fprintf() and fscanf() functions take the FILE pointer as the first argument instead of as the last argument.

The fgets() and fputs() Functions

You met fgets() in Chapter 11. The fgets() function takes three arguments to the gets() function's one. The first argument, as with gets() , is the address (type char * ) where input should be stored. The second argument is an integer representing the maximum size of the input string. The final argument is the file pointer identifying the file to be read. A function call, then, looks like this:

 fgets(buf, MAX, fp); 

Here, buf is the name of a char array, MAX is the maximum size of the string, and fp is the pointer-to- FILE .

The fgets() function reads input through the first newline character or until one fewer than the upper limit of characters is read or until the end of file is found; fgets() then adds a terminating null character to form a string. Therefore, the upper limit represents the maximum number of characters plus the null character. If fgets() reads in a whole line before running into the character limit, it adds the newline character marking the end of the line into the string, just before the null character. Here it differs from gets() , which reads the newline but discards it.

Like gets() , fgets() returns the value NULL when it encounters EOF . You can use this to check for the end of a file. Otherwise, it returns the address passed to it.

The fputs() function takes two arguments: first, an address of a string, and then a file pointer. It writes the string found at the pointed-to location into the indicated file. Unlike puts() , fputs() does not append a newline when it prints. A function call looks like this:

 fputs(buf, fp); 

Here, buf is the string address, and fp identifies the target file.

Because fgets() keeps the newline and fputs() doesn't add one, they work well in tandem. Listing 12.4 shows an echo program using these two functions.

Listing 12.4 The echo.c program.
 /* echo.c -- using fgets() and fputs() */ #include <stdio.h> #define MAXLINE 20 int main(void) {     char line[MAXLINE];     while (fgets(line, MAXLINE, stdin) != NULL &&              line[0] != '\n')        fputs(line, stdout);     return 0;     } 

When you press the Enter key at the beginning of a line, fgets() reads the newline and places it into the first element of the array line . Use that fact to terminate the input loop. Encountering end of file also terminates it. (Listing 12.3 tested for '\0' instead of '\n' because gets() discards the newline.)

Here is a sample run. Do you notice anything odd?

  The silent knight  The silent knight  strode solemnly down the dank and dark hall.  strode solemnly down the dank and dark hall.  [enter]  

The program works fine. This should seem surprising because the second line you entered contains 44 characters, and the line array holds only 20, including the newline character! What happened ? When fgets() read the second line, it read just the first 19 characters, through the w in down . They were copied into line , which fputs() printed. Because fgets() hadn't reached the end of a line, line did not contain a newline character, so fputs() didn't print a newline. The third call to fgets() resumed where the second call left off. Therefore, it read the next 19 characters into line , beginning with the n after the w in down . This next block replaced the previous contents of line and, in turn , was printed on the same line as the output. Remember, the last output didn't have a newline. In short, fgets() read the second line in chunks of 19 characters, and fputs() printed it in the same-size chunks.

This program also terminates input if a line has exactly 19 characters. In that case, fgets() stops reading input after the 19 characters, so the next call to fgets() starts with the newline at the end of the line. This newline becomes the first character read, thus terminating the loop. So although the program worked with the sample input, it doesn't work correctly in all cases. You really should use a storage array big enough to hold entire lines.

You might be wondering why the program didn't print the first 19 characters of the second line as soon as you typed them. That is where screen buffering comes in. The second line wasn't sent to the screen until the newline character had been reached.

Commentary: gets() and fgets()

Because fgets() can be used to prevent storage overflow, it is a better function than gets() for serious programming. Because it does read a newline into a string and because puts() appends a newline to output, fgets() should be used with fputs() , not puts() . Otherwise, one newline in input can become two on output.

The six I/O functions we have just discussed should give you tools aplenty for reading and writing text files. So far, we have used them only for sequential access, that is, processing the file contents in order. Next, we look at random access ”in other words, accessing the contents in any order you want.

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