Yet Another Version of 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.


Note

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.


Tip

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.

Listing 5.19. textin4.cpp


// 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;
}



Note

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().

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

Image

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().)

Nested Loops and Two-Dimensional Arrays

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.

Figure 5.5. An array of arrays.

Image

The expression maxtemps[0] is the first element of the maxtemps array; hence maxtemps[0] is itself an array of five ints. 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).

Figure 5.6. Accessing array elements with subscripts.

Image

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.

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

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