The call to cin.peek() peeks at the next input character and assigns its value to ch. Then the while loop test condition checks that ch is neither a period nor a newline. If this is the case, the loop reads the character into the array and updates the array index. When the loop terminates, the period or newline character remains in the input stream, positioned to be the first character read by the next input operation. Then the code appends a null character to the array, making it a string.
The gcount() method returns the number of characters read by the last unformatted extraction method. That means characters read by a get(), getline(), ignore(), or read() method but not by the extraction operator (>>), which formats input to fit particular data types. For example, suppose you’ve just used cin.get(myarray, 80) to read a line into the myarray array and you want to know how many characters were read. You could use the strlen() function to count the characters in the array, but it would be quicker to use cin.gcount() to report how many characters were just read from the input stream.
The putback() function inserts a character back in the input string. The inserted character then becomes the first character read by the next input statement. The putback() method takes one char argument, which is the character to be inserted, and it returns type istream &, which allows the call to be concatenated with other istream methods. Using peek() is like using get() to read a character and then using putback() to place the character back in the input stream. However, putback() gives you the option of putting back a character that is different from the one just read.
Listing 17.14 uses two approaches to read and echo input up to, but not including, a # character. The first approach reads through the # character and then uses putback() to insert the character back into the input. The second approach uses peek() to look ahead before reading input.
Listing 17.14. peeker.cpp
// peeker.cpp -- some istream methods
#include
int main()
{
using std::cout;
using std::cin;
using std::endl;
// read and echo input up to a # character
char ch;
while(cin.get(ch)) // terminates on EOF
{
if (ch != '#')
cout << ch;
else
{
cin.putback(ch); // reinsert character
break;
}
}
if (!cin.eof())
{
cin.get(ch);
cout << endl << ch << " is next input character.\n";
}
else
{
cout << "End of file reached.\n";
std::exit(0);
}
while(cin.peek() != '#') // look ahead
{
cin.get(ch);
cout << ch;
}
if (!cin.eof())
{
cin.get(ch);
cout << endl << ch << " is next input character.\n";
}
else
cout << "End of file reached.\n";
return 0;
}
Here is a sample run of the program in Listing 17.14:
I used a #3 pencil when I should have used a #2.
I used a
# is next input character.
3 pencil when I should have used a
# is next input character.
Program Notes
Let’s look more closely at some of the code in Listing 17.14. The first approach uses a while loop to read input:
while(cin.get(ch)) // terminates on EOF
{
if (ch != '#')
cout << ch;
else
{
cin.putback(ch); // reinsert character
break;
}
}
The expression cin.get(ch) returns false on reaching the end-of-file condition, so simulating end-of-file from the keyboard terminates the loop. If the # character shows up first, the program puts the character back in the input stream and uses a break statement to terminate the loop.
The second approach is simpler in appearance:
while(cin.peek() != '#') // look ahead
{
cin.get(ch);
cout << ch;
}
The program peeks at the next character. If it is not the # character, the program reads the next character, echoes it, and peeks at the next character. This continues until the terminating character shows up.
Now let’s look, as promised, at an example—Listing 17.15—that uses peek() to determine whether an entire line has been read. If only part of a line fits in the input array, the program discards the rest of the line.
Listing 17.15. truncate.cpp
// truncate.cpp -- using get() to truncate input line, if necessary
#include
const int SLEN = 10;
inline void eatline() { while (std::cin.get() != '\n') continue; }
int main()
{
using std::cin;
using std::cout;
using std::endl;
char name[SLEN];
char title[SLEN];
cout << "Enter your name: ";
cin.get(name,SLEN);
if (cin.peek() != '\n')
cout << "Sorry, we only have enough room for "
<< name << endl;
eatline();
cout << "Dear " << name << ", enter your title: \n";
cin.get(title,SLEN);
if (cin.peek() != '\n')
cout << "We were forced to truncate your title.\n";
eatline();
cout << " Name: " << name
<< "\nTitle: " << title << endl;
return 0;
}
Here is a sample run of the program in Listing 17.15:
Enter your name: Ella Fishsniffer
Sorry, we only have enough room for Ella Fish
Dear Ella Fish, enter your title:
Executive Adjunct
We were forced to truncate your title.
Name: Ella Fish
Title: Executive
Note that the following code makes sense whether or not the first input statement reads the entire line: