cin.get()
Nostalgic C users might yearn for C’s character I/O functions, getchar()
and putchar()
. They are available in C++ if you want them. You just use the stdio.h
header file as you would in C (or use the more current cstdio
). Or you can use member functions from the istream
and ostream
classes that work in much the same way. Let’s look at that approach next.
The cin.get()
member function with no arguments returns the next character from the input. That is, you use it in this way:
ch = cin.get();
(Recall that cin.get(ch)
returns an object, not the character read.) This function works much the same as C’s getchar()
, returning the character code as a type int
value. Similarly, you can use the cout.put()
function (see Chapter 3, “Dealing with Data”) to display the character:
cout.put(ch);
It works much like C’s putchar()
, except that its argument should be type char
instead of type int
.
Originally, the put()
member had the single prototype put(char)
. You could pass to it an int
argument, which would then be type cast to char
. The Standard also calls for a single prototype. However, some C++ implementations provide three prototypes: put(char)
, put(signed char)
, and put(unsigned char)
. Using put()
with an int
argument in these implementations generates an error message because there is more than one choice for converting the int
. An explicit type cast, such as cin.put(char(ch))
, works for int
types.
To use cin.get()
successfully, you need to know how it handles the EOF condition. When the function reaches the EOF, there are no more characters to be returned. Instead, cin.get()
returns a special value, represented by the symbolic constant EOF
. This constant is defined in the iostream
header file. The EOF
value must be different from any valid character value so that the program won’t confuse EOF
with a regular character. Typically, EOF
is defined as the value -1
because no character has an ASCII code of -1
, but you don’t need to know the actual value. You can just use EOF
in a program. For example, the heart of Listing 5.18 looks like this:
char ch;
cin.get(ch);
while (cin.fail() == false) // test for EOF
{
cout << ch;
++count;
cin.get(ch);
}
You can use int ch
, replace cin.get(char)
with cin.get()
, replace cout
with cout.put()
, and replace the cin.fail()
test with a test for EOF
:
int ch; /// for compatibility with EOF value
ch = cin.get();
while (ch != EOF)
{
cout.put(ch); // cout.put(char(ch)) for some implementations
++count;
ch = cin.get();
}
If ch
is a character, the loop displays it. If ch
is EOF
, the loop terminates.
You should realize that EOF
does not represent a character in the input. Instead, it’s a signal that there are no more characters.
There’s a subtle but important point about using cin.get()
beyond the changes made so far. Because EOF
represents a value outside the valid character codes, it’s possible that it might not be compatible with the char
type. For example, on some systems type char
is unsigned, so a char
variable could never have the usual EOF
value of -1
. For this reason, if you use cin.get()
(with no argument) and test for EOF
, you must assign the return value to type int
instead of to type char
. Also if you make ch
type int
instead of type char
, you might have to do a type cast to char
when displaying ch
.
Listing 5.19 incorporates the cin.get()
approach into a new version of Listing 5.18. It also condenses the code by combining character input with the while
loop test.
// textin4.cpp -- reading chars with cin.get()
#include <iostream>
int main(void)
{
using namespace std;
int ch; // should be int, not char
int count = 0;
while ((ch = cin.get()) != EOF) // test for end-of-file
{
cout.put(char(ch));
++count;
}
cout << endl << count << " characters read
";
return 0;
}
Some systems either do not support simulated EOF from the keyboard or support it imperfectly, and that may prevent the example in Listing 5.19 from running as described. If you have been using cin.get()
to freeze the screen until you can read it, that won’t work here because detecting the EOF turns off further attempts to read input. However, you can use a timing loop like that in Listing 5.14 to keep the screen visible for a while. Or you can use cin.clear(),
as described in Chapter 17, to reset the input stream.
Here’s a sample run of the program in Listing 5.19:
The sullen mackerel sulks in the shadowy shallows.<ENTER>
The sullen mackerel sulks in the shadowy shallows.
Yes, but the blue bird of happiness harbors secrets.<ENTER>
Yes, but the blue bird of happiness harbors secrets.
<CTRL>+<Z><ENTER>
104 characters read
Let’s analyze the loop condition:
while ((ch = cin.get()) != EOF)
The parentheses that enclose the subexpression ch = cin.get()
cause the program to evaluate that expression first. To do the evaluation, the program first has to call the cin.get()
function. Next, it assigns the function return value to ch
. Because the value of an assignment statement is the value of the left operand, the whole subexpression reduces to the value of ch
. If this value is EOF
, the loop terminates; otherwise, it continues. The test condition needs all the parentheses. Suppose you leave some parentheses out:
while (ch = cin.get() != EOF)
The !=
operator has higher precedence than =
, so first the program compares cin.get()
’s return value to EOF
. A comparison produces a false
or true
result; that bool
value is converted to 0
or 1
, and that’s the value that gets assigned to ch
.
Using cin.get(ch)
(with an argument) for input, on the other hand, doesn’t create any type problems. Remember that the cin.get(char)
function doesn’t assign a special value to ch
at the EOF. In fact, it doesn’t assign anything to ch
in that case. ch
is never called on to hold a non-char
value. Table 5.3 summarizes the differences between cin.get(char)
and cin.get()
.
So which should you use, cin.get()
or cin.get(char)
? The form with the character argument is integrated more fully into the object approach because its return value is an istream
object. This means, for example, that you can chain uses. For example, the following code means read the next input character into ch1
and the following input character into ch2
:
cin.get(ch1).get(ch2);
This works because the function call cin.get(ch1)
returns the cin
object, which then acts as the object to which get(ch2)
is attached.
Probably the main use for the get()
form is to let you make quick-and-dirty conversions from the getchar()
and putchar()
functions of stdio.h
to the cin.get()
and cout.put()
methods of iostream
. You just replace one header file with the other and globally replace getchar()
and putchar()
with their act-alike method equivalents. (If the old code uses a type int
variable for input, you have to make further adjustments if your implementation has multiple prototypes for put()
.)
Earlier in this chapter you saw that the for
loop is a natural tool for processing arrays. Now let’s go a step further and look at how a for
loop within a for
loop (nested loops) serves to handle two-dimensional arrays.
First, let’s examine what a two-dimensional array is. The arrays used so far in this chapter are termed one-dimensional arrays because you can visualize each array as a single row of data. You can visualize a two-dimensional array as being more like a table, having both rows and columns of data. You can use a two-dimensional array, for example, to represent quarterly sales figures for six separate districts, with one row of data for each district. Or you can use a two-dimensional array to represent the position of RoboDork on a computerized game board.
C++ doesn’t provide a special two-dimensional array type. Instead, you create an array for which each element is itself an array. For example, suppose you want to store maximum temperature data for five cities over a 4-year period. In that case, you can declare an array as follows:
int maxtemps[4][5];
This declaration means that maxtemps
is an array with four elements. Each of these elements is an array of five integers (see Figure 5.5). You can think of the maxtemps
array as representing four rows of five temperature values each.
The expression maxtemps[0]
is the first element of the maxtemps
array; hence maxtemps[0]
is itself an array of five int
s. The first element of the maxtemps[0]
array is maxtemps[0][0]
, and this element is a single int
. Thus, you need to use two subscripts to access the int
elements. You can think of the first subscript as representing the row and the second subscript as representing the column (see Figure 5.6).
Suppose you want to print all the array contents. In that case, you can use one for
loop to change rows and a second, nested, for
loop to change columns:
for (int row = 0; row < 4; row++)
{
for (int col = 0; col < 5; ++col)
cout << maxtemps[row][col] << " ";
cout << endl;
}
For each value of row
, the inner for
loop cycles through all the col
values. This example prints a tab character (
in C++ escape character notation) after each value and a newline character after each complete row.
18.191.168.8