Other istream Class Methods

Chapters 3 through 5 discuss the get() and getline() methods. As you may recall, they provide the following additional input capabilities:

• The get(char &) and get(void) methods provide single-character input that doesn’t skip over white space.

• The get(char *, int, char) and getline(char *, int, char) functions by default read entire lines rather than single words.

These are termed unformatted input functions because they simply read character input as it is, without skipping over white space and without performing data conversions.

Let’s look at these two groups of istream class member functions.

Single-Character Input

When used with a char argument or no argument at all, the get() methods fetch the next input character, even if it is a space, tab, or newline character. The get(char & ch) version assigns the input character to its argument, and the get(void) version uses the input character, converted to an integer type (typically int), as its return value.

The get(char &) Member Function

Let’s try get(char &) first. Suppose you have the following loop in a program:

int ct = 0;
char ch;
cin.get(ch);
while (ch != ' ')
{
    cout << ch;
    ct++;
    cin.get(ch);
}
cout << ct << endl;

Next, suppose you type the following optimistic input:

I C++ clearly.<Enter>

Pressing the Enter key sends this input line to the program. The program fragment reads the I character, displays it with cout, and increments ct to 1. Next, it reads the space character following the I, displays it, and increments ct to 2. This continues until the program processes the Enter key as a newline character and terminates the loop. The main point here is that, by using get(ch), the code reads, displays, and counts the spaces as well as the printing characters.

Suppose, instead, that the program tried to use >>:

int ct = 0;
char ch;
cin >> ch;
while (ch != ' ')    // FAILS
{
    cout << ch;
    ct++;
    cin >> ch;
}
cout << ct << endl;

First, the code would skip the spaces, thus not counting them and compressing the corresponding output to this:

IC++clearly.

Worse, the loop would never terminate! Because the extraction operator skips newlines, the code would never assign the newline character to ch, so the while loop test would never terminate the loop.

The get(char &) member function returns a reference to the istream object used to invoke it. This means you can concatenate other extractions following get(char &):

char c1, c2, c3;
cin.get(c1).get(c2) >> c3;

First, cin.get(c1) assigns the first input character to c1 and returns the invoking object, which is cin. This reduces the code to cin.get(c2) >> c3, which assigns the second input character to c2. The function call returns cin, reducing the code to cin >> c3. This, in turn, assigns the next non-white-space character to c3. Note that c1 and c2 could wind up being assigned white space, but c3 couldn’t.

If cin.get(char &) encounters the end of a file, either real or simulated from the keyboard (Ctrl+Z for DOS and Windows command prompt mode, Ctrl+D at the beginning of a line for Unix), it does not assign a value to its argument. This is quite right because if the program has reached the end of the file, there is no value to be assigned. Furthermore, the method calls setstate(failbit), which causes cin to test as false:

char ch;
while (cin.get(ch))
{
     // process input
}

As long as there’s valid input, the return value for cin.get(ch) is cin, which evaluates as true, so the loop continues. Upon reaching end-of-file, the return value evaluates as false, terminating the loop.

The getchar() Member Function

The get(void) member function also reads white space, but it uses its return value to communicate input to a program. So you would use it this way:

int ct = 0;
char ch;
ch = cin.get();      // use return value
while (ch != ' ')
{
    cout << ch;
    ct++;
    ch = cin.get();
}
cout << ct << endl;

The get(void) member function returns type int (or some larger integer type, depending on the character set and locale). This makes the following invalid:

char c1, c2, c3;
cin.get().get() >> c3;  // not valid

Here cin.get() returns a type int value. Because that return value is not a class object, you can’t apply the membership operator to it. Thus, you get a syntax error. However, you can use get() at the end of an extraction sequence:

char c1;
cin.get(c1).get();   // valid

The fact that get(void) returns type int means you can’t follow it with an extraction operator. But because cin.get(c1) returns cin, it makes it a suitable prefix to get(). This particular code would read the first input character, assign it to c1, and then read the second input character and discard it.

Upon reaching the end-of-file, real or simulated, cin.get(void) returns the value EOF, which is a symbolic constant provided by the iostream header file. This design feature allows the following construction for reading input:

int ch;
while ((ch = cin.get()) != EOF)
{
    // process input
}

You should use type int for ch instead of type char here because the value EOF may not be expressed as a char type.

Chapter 5, “Loops and Relational Expressions,” describes these functions in a bit more detail, and Table 17.5 summarizes the features of the single-character input functions.

Table 17.5. cin.get(ch) Versus cin.get()

Image

Which Form of Single-Character Input to Use?

Given the choice of >>, get(char &), and get(void), which should you use? First, you need to decide whether you want input to skip over white space. If skipping white space is convenient, you should use the extraction operator, >>. For example, skipping white space is convenient for offering menu choices:

cout  << "a. annoy client         b. bill client "
      << "c. calm client          d. deceive client "
      << "q. ";
cout  << "Enter a, b, c, d, or q: ";
char ch;
cin >> ch;
while (ch != 'q')
{
    switch(ch)
    {
        ...
    }
    cout << "Enter a, b, c, d, or q: ";
    cin >> ch;
}

To enter, say, a b response, you type b and press Enter, generating the two-character response b . If you used either form of get(), you would have to add code to process that character on each loop cycle, but the extraction operator conveniently skips it. (If you’ve programmed in C, you’ve probably encountered a situation in which the newline appears to the program as an invalid response. It’s an easy problem to fix, but it is a nuisance.)

If you want a program to examine every character, you should use one of the get() methods. For example, a word-counting program could use white space to determine when a word came to an end. Of the two get() methods, the get(char &) method has the classier interface. The main advantage of the get(void) method is that it closely resembles the standard C getchar() function, which means you can convert a C program to a C++ program by including iostream instead of stdio.h, globally replacing getchar() with cin.get(), and globally replacing C’s putchar(ch) with cout.put(ch).

String Input: getline(), get(), and ignore()

Next, let’s review the string input member functions introduced in Chapter 4, “Compound Types”. The getline() member function and the string-reading version of get() both read strings, and both have the same function signatures (here simplified from the more general template declaration):

istream & get(char *, int, char);
istream & get(char *, int);
istream & getline(char *, int, char);
istream & getline(char *, int);

The first argument, recall, is the address of the location to place the input string. The second argument is one greater than the maximum number of characters to be read. (The additional character leaves space for the terminating null character used in storing the input as a string.) The third argument specifies a character to act as a delimiter to input. The versions with just two arguments use the newline character as a delimiter. Each function reads up to the maximum characters or until it encounters the delimiter character, whichever comes first.

For example, the following code reads character input into the character array line:

char line[50];
cin.get(line, 50);

The cin.get() function quits reading input into the array after encountering 49 characters or, by default, after encountering a newline character, whichever comes first. The chief difference between get() and getline() is that get() leaves the newline character in the input stream, making it the first character seen by the next input operation, whereas getline() extracts and discards the newline character from the input stream.

Chapter 4 illustrated using the two-argument form for these two member functions. Now let’s look at the three-argument versions. The third argument is the delimiter character. Encountering the delimiter character causes input to cease, even if the maximum number of characters hasn’t been reached. So by default, both methods quit reading input if they reach the end of a line before reading the allotted number of characters. Just as in the default case, get() leaves the delimiter character in the input queue, and getline() does not.

Listing 17.13 demonstrates how getline() and get() work. It also introduces the ignore() member function. ignore() takes two arguments: a number specifying a maximum number of characters to read and a character that acts as a delimiter character for input. For example, the following function call reads and discards the next 255 characters or up through the first newline character, whichever comes first:

cin.ignore(255, ' '),

The prototype provides defaults of 1 and EOF for the two arguments, and the function return type is istream &:

istream & ignore(int = 1, int = EOF);

(The EOF default value causes ignore() to read up to the specified number of characters or until end-of-file, whichever comes first.)

The function returns the invoking object. This lets you concatenate function calls, as in the following:

cin.ignore(255, ' ').ignore(255, ' '),

Here the first ignore() method reads and discards one line, and the second call reads and discards the second line. Together the two functions read through two lines.

Now check out Listing 17.13.

Listing 17.13. get_fun.cpp


// get_fun.cpp -- using get() and getline()
#include <iostream>
const int Limit = 255;

int main()
{
    using std::cout;
    using std::cin;
    using std::endl;

    char input[Limit];

    cout << "Enter a string for getline() processing: ";
    cin.getline(input, Limit, '#'),
    cout << "Here is your input: ";
    cout << input << " Done with phase 1 ";

    char ch;
    cin.get(ch);
    cout << "The next input character is " << ch << endl;

    if (ch != ' ')
        cin.ignore(Limit, ' '),    // discard rest of line

    cout << "Enter a string for get() processing: ";
    cin.get(input, Limit, '#'),
    cout << "Here is your input: ";
    cout << input << " Done with phase 2 ";

    cin.get(ch);
    cout << "The next input character is " << ch << endl;

    return 0;
}


Here is a sample run of the program in Listing 17.13:

Enter a string for getline() processing:
Please pass
me a #3 melon!
Here is your input:
Please pass
me a
Done with phase 1
The next input character is 3
Enter a string for get() processing:
I still
want my #3 melon!
Here is your input:
I still
want my
Done with phase 2
The next input character is #

Note that the getline() function discards the # termination character in the input, and the get() function does not.

Unexpected String Input

Some forms of input for get(char *, int) and getline() affect the stream state. As with the other input functions, encountering end-of-file sets eofbit, and anything that corrupts the stream, such as device failure, sets badbit. Two other special cases are no input and input that meets or exceeds the maximum number of characters specified by the function call. Let’s look at those cases now.

If either method fails to extract any characters, the method places a null character into the input string and uses setstate() to set failbit. When would a method fail to extract any characters? One possibility is if an input method immediately encounters end-of-file. For get(char *, int), another possibility is if you enter an empty line:

char temp[80];
while (cin.get(temp,80))  // terminates on empty line
      ...

Interestingly, an empty line does not cause getline() to set failbit. That’s because getline() still extracts the newline character, even if it doesn’t store it. If you want a getline() loop to terminate on an empty line, you can write it this way:

char temp[80];
while (cin.getline(temp,80) && temp[0] != '') // terminates on empty line

Now suppose the number of characters in the input queue meets or exceeds the maximum specified by the input method. First, consider getline() and the following code:

char temp[30];
while (cin.getline(temp,30))

The getline() method will read consecutive characters from the input queue, placing them in successive elements of the temp array, until (in order of testing) end-of-file is encountered, until the next character to be read is the newline character, or until 29 characters have been stored. If end-of-file is encountered, eofbit is set. If the next character to be read is a newline character, that character is read and discarded. And if 29 characters were read, failbit is set, unless the next character is a newline. Thus, an input line of 30 characters or more will terminate input.

Now consider the get(char *, int) method. It tests the number of characters first, end-of-file second, and for the next character being a newline third. It does not set the failbit flag if it reads the maximum number of characters. Nonetheless, you can tell if too many input characters caused the method to quit reading. You can use peek() (see the next section) to examine the next input character. If it’s a newline, then get() must have read the entire line. If it’s not a newline, then get() must have stopped before reaching the end. This technique doesn’t necessarily work with getline() because getline() reads and discards the newline, so looking at the next character doesn’t tell you anything. But if you use get(), you have the option of doing something if less than an entire line is read. The next section includes an example of this approach. Meanwhile, Table 17.6 summarizes these behaviors.

Table 17.6. Input Behavior

Image

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.105.215