Terminating Keyboard Input

I l @ ve RuBoard

Terminating Keyboard Input

The program halts when # is entered, which is convenient as long as you exclude that character from normal input. As you've seen, however, # can show up in normal input. Ideally, you'd like a terminating character that normally does not show up in text. Such a character won't pop up accidentally in the middle of some input, stopping the program before you want it to stop. C has an answer to this need, but, to understand it, you need to know how C handles files.

Files, Streams, and Keyboard Input

A file is an area of memory in which information is stored. Normally, a file is kept in some sort of permanent memory, such as a floppy disk, a hard disk, or a tape. You are doubtless aware of the importance of files to computer systems. For instance, your C programs are kept in files, and the programs used to compile your programs are kept in files. This last example points out that some programs need to be able to access particular files. When you compile a program stored in a file called echo.c , the compiler opens the echo.c file and reads its contents. When the compiler finishes, it closes the file. Other programs, such as word processors, not only open , read, and close files, they also write to them.

C, being powerful, flexible, and so on, has many library functions for opening, reading, writing, and closing files. On one level, it can deal with files by using the basic file tools of the host operating system. This is called low-level I/O . Because of the many differences among computer systems, it is impossible to create a standard library of universal low-level I/O functions, and ANSI C does not attempt to do so; however, C also deals with files on a second level called the standard I/O package. This involves creating a standard model and a standard set of I/O functions for dealing with files. At this higher level, differences between systems are handled by specific C implementations so that you deal with a uniform interface.

What sort of differences are we talking about? Different systems, for example, store files differently. Some store the file contents in one place and information about the file elsewhere. Some build a description of the file into the file itself. In dealing with text, some systems use a single newline character to mark the end of a line. Others might use the combination of the carriage return and linefeed characters to represent the end of a line. Some systems measure file sizes to the nearest byte; some measure in blocks of bytes.

When you use the standard I/O package, you are shielded from these differences. Therefore, to check for a newline, you can use if (ch == '\n') . If the system actually uses the carriage-return/linefeed combination, the I/O functions automatically translate back and forth between the two representations.

Conceptually, the C program deals with a stream instead of directly with a file. A stream is an idealized flow of data to which the actual input or output is mapped. That means various kinds of input with differing properties are represented by streams with more uniform properties. The process of opening a file then becomes one of associating a stream with the file, and reading and writing take place via the stream.

Chapter 12 discusses files in greater detail. For this chapter, simply note that C treats input and output devices the same as it treats regular files on storage devices. In particular, the keyboard and the display device are treated as files opened automatically by every C program. Keyboard input is represented by a stream called stdin , and output to the screen (or teletype, or other output device) is represented by a stream called stdout . The getchar () , putchar () , printf() , and scanf() functions are all members of the standard I/O package, and they deal with these two streams.

One implication of all this is that you can use the same techniques with keyboard input as you do with files. For example, a program reading a file needs a way to detect the end of the file so that it knows where to stop reading. Therefore, C input functions come equipped with a built-in end-of-file detector. Because keyboard input is treated like a file, you should be able to use that end-of-file detector to terminate keyboard input, too. Let's see how this is done, beginning with files.

The End of File

A computer operating system needs some way to tell where each file begins and ends. One method to detect the end of a file is to place a special character in the file to mark the end. This is the method used, for example, in CP/M, IBM-DOS, and MS-DOS text files. These operating systems use (or once used) the Ctrl+Z character to mark the end of files. (Ctrl+Z is the character generated by holding down the Ctrl key while typing the Z key.) Figure 8.2 illustrates this approach.

Figure 8.2. A file with an end-of-file marker.
graphics/08fig02.jpg

A second approach is for the operating system to store information on the size of the file. If a file has 3,000 bytes and a program has read 3,000 bytes, then the program has reached the end. MS-DOS and its relatives use this approach for binary files because this method allows the files to hold all characters, including Ctrl+Z. Newer versions of DOS also use this approach for text files. UNIX uses this approach for all files.

C handles this variety of methods by having the getchar() function return a special value when the end of a file is reached, regardless of how the operating system actually detects the end of file. The name given to this value is EOF (end of file). Therefore, the return value for getchar() when it detects an end of file is EOF . The scanf() function also returns EOF on detecting the end of a file. Typically, EOF is defined in the stdio. h file as follows :

 #define EOF (-1) 

Why -1 ? Normally, getchar() returns a value in the range through 127 because those are values corresponding to the standard character set, but it might return values from through 255 if the system recognizes an extended character set. In either case, the value -1 does not correspond to any character, so it can be used to signal the end of a file.

Some systems may define EOF to be a value other than -1 , but the definition is always different from a return value produced by a legitimate input character. If you include the stdio.h file and use the EOF symbol, you don't have to worry about the numeric definition. The important point is that EOF represents a value that signals the end of a file was detected ; it is not a symbol actually found in the file.

Okay, how can you use EOF in a program? Compare the return value of getchar() with EOF . If they are different, you have not yet reached the end of a file. In other words, you can use an expression like this:

 while ((ch = getchar()) != EOF) 

What if you are reading keyboard input and not a file? Most systems (but not all) have a way to simulate an end-of-file condition from the keyboard. Knowing that, you can rewrite the basic read and echo program, as shown in Listing 8.2.

Listing 8.2 The echo_eof.c program.
 /* echo_eof.c -- repeats input to end of file */ #include <stdio.h> int main (void) {   int ch;   while ((ch = getchar()) != EOF)        putchar(ch);   return 0; } 

Note these points:

  • You don't have to define EOF because stdio.h takes care of that.

  • You don't have to worry about the actual value of EOF because the #define statement in stdio.h enables you to use the symbolic representation EOF .

  • The variable ch is changed from type char to type int because char variables may be represented by unsigned integers in the range to 255 , but EOF may have the numeric value -1 . That is an impossible value for an unsigned char variable, but not for an int . Fortunately, getchar() is actually type int itself, so it can read the EOF character. Implementations that use a signed char type may get by with declaring ch as type char , but it is better to use the more general form.

  • The fact that ch is an integer doesn't faze putchar() . It still prints the character equivalent.

  • To use this program on keyboard input, you need a way to type the EOF character. No, you can't just type the letters E-O-F , and you can't just type -1 . (Typing -1 would transmit two characters: a hyphen and the digit 1 .) Instead, you have to find out what your system requires. On most UNIX systems, for example, typing Ctrl+D at the beginning of a line causes the end-of-file signal to be transmitted. Many microcomputing systems recognize a Ctrl+Z typed anywhere on a line as an end-of-file signal.

Here is a buffered example of running echo_eof.c on a UNIX system:

  She walks in beauty, like the night  She walks in beauty, like the night  Of cloudless climes and starry skies...  Of cloudless climes and starry skies...  Lord Byron  Lord Byron  [Ctrl+D]  

Each time you press Enter, the characters stored in the buffer are processed , and a copy of the line is printed. This continues until you simulate the end of file, UNIX-style. On a PC, you would type Ctrl+Z instead.

Let's stop for a moment and think about the possibilities for echo_eof.c . It copies onto the screen whatever input you feed it. Suppose you could somehow feed a file to it. Then it would print the contents of the file onto the screen, stopping when it reached the end of the file, for it would find an EOF signal then. Suppose instead that you could find a way to direct the program's output to a file. Then you could enter data from the keyboard and use echo_eof.c to store what you type in a file. Suppose you could do both simultaneously : Direct input from one file into echo_eof.c and send the output to another file. Then you could use echo_eof.c to copy files. This little program has the potential to look at the contents of files, to create new files, and to make copies of files ”pretty good for such a short program! The key is to control the flow of input and output, and that is the next topic.

Simulated EOF and Graphical Interfaces

The concept of simulated EOF developed in a command-line environment using a text interface. In such environments, the user interacts with a program through keystrokes, and the operating system generates the EOF signal. Some practices don't translate particularly well to graphical interfaces, such as Windows and the Macintosh, with more complex user interfaces. For them, some behaviors result from the particular implementation rather than from the operating system. For example, a simulated EOF is not a basic Macintosh concept. However, Metrowerks CodeWarrior for the Mac provides added support that recognizes Ctrl+Z as the end-of-file simulation, but Symantec C for the Mac chose to implement Ctrl+D as the end-of-file equivalent.

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