Let’s try another approach. The istream class has another member function, get(), which comes in several variations. One variant works much like getline(). It takes the same arguments, interprets them the same way, and reads to the end of a line. But rather than read and discard the newline character, get() leaves that character in the input queue. Suppose you use two calls to get() in a row:
cin.get(name, ArSize);
cin.get(dessert, Arsize); // a problem
Because the first call leaves the newline character in the input queue, that newline character is the first character the second call sees. Thus, get() concludes that it’s reached the end of line without having found anything to read. Without help, get() just can’t get past that newline character.
Fortunately, there is help in the form of a variation of get(). The call cin.get() (with no arguments) reads the single next character, even if it is a newline, so you can use it to dispose of the newline character and prepare for the next line of input. That is, this sequence works:
cin.get(name, ArSize); // read first line
cin.get(); // read newline
cin.get(dessert, Arsize); // read second line
Another way to use get() is to
cin.get(name, ArSize).get(); // concatenate member functions
What makes this possible is that cin.get(name, ArSize) returns the cin object, which is then used as the object that invokes the get() function. Similarly, the following statement reads two consecutive input lines into the arrays name1 and name2; it’s equivalent to making two separate calls to cin.getline():
cin.getline(name1, ArSize).getline(name2, ArSize);
Listing 4.5 uses concatenation. In Chapter 11, “Working with Classes,” you’ll learn how to incorporate this feature into your class definitions.
Listing 4.5. instr3.cpp
// instr3.cpp -- reading more than one word with get() & get()
#include
int main()
{
using namespace std;
const int ArSize = 20;
char name[ArSize];
char dessert[ArSize];
cout << "Enter your name:\n";
cin.get(name, ArSize).get(); // read string, newline
cout << "Enter your favorite dessert:\n";
cin.get(dessert, ArSize).get();
cout << "I have some delicious " << dessert;
cout << " for you, " << name << ".\n";
return 0;
}
Here is a sample run of the program in Listing 4.5:
Enter your name:
Mai Parfait
Enter your favorite dessert:
Chocolate Mousse
I have some delicious Chocolate Mousse for you, Mai Parfait.
One thing to note is how C++ allows multiple versions of functions, provided that they have different argument lists. If you use, say, cin.get(name, ArSize), the compiler notices you’re using the form that puts a string into an array and sets up the appropriate member function. If, instead, you use cin.get(), the compiler realizes you want the form that reads one character. Chapter 8, “Adventures in Functions,” explores this feature, which is called
Why use get() instead of getline() at all? First, older implementations may not have getline(). Second, get() lets you be a bit more careful. Suppose, for example, you used get() to read a line into an array. How can you tell if it read the whole line rather than stopped because the array was filled? Look at the next input character. If it is a newline character, then the whole line was read. If it is not a newline character, then there is still more input on that line. Chapter 17 investigates this technique. In short, getline() is a little simpler to use, but get() makes error checking simpler. You can use either one to read a line of input; just keep the slightly different behaviors in mind.
Empty Lines and Other Problems
What happens after getline() or get() reads an empty line? The original practice was that the next input statement picked up where the last getline() or get() left off. However, the current practice is that after get() (but not getline()) reads an empty line, it sets something called the
cin.clear();
Another potential problem is that the input string could be longer than the allocated space. If the input line is longer than the number of characters specified, both getline() and get() leave the remaining characters in the input queue. However, getline() additionally sets the failbit and turns off further input.
Chapters 5, 6, and 17 investigate these properties and how to program around them.
Mixing String and Numeric Input
Mixing numeric input with line-oriented string input can cause problems. Consider the simple program in Listing 4.6.
Listing 4.6. numstr.cpp
// numstr.cpp -- following number input with line input
#include
int main()
{
using namespace std;
cout << "What year was your house built?\n";
int year;
cin >> year;