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 != '\n') // 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 != '\n')
{
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()
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\n"
<< "c. calm client d. deceive client\n"
<< "q.\n";
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;
}