In this section, we are going to read user input into different variables, and see how to handle errors, as well as how to do a little bit more complex tokenizing of input into useful chunks:
- We only need iostream this time. So, let's include this single header and declare that we use the std namespace by default:
#include <iostream>
using namespace std;
- Let's first prompt the user to enter two numbers. We will parse them into an int and a double variable. The user can separate them with white space. 1 2.3, for example, is a valid input:
int main()
{
cout << "Please Enter two numbers:n> ";
int x;
double y;
- Parsing and error checking is done at the same time in the condition part of our if branch. Only if both the numbers could be parsed are they meaningful to us and we print them:
if (cin >> x >> y) {
cout << "You entered: " << x
<< " and " << y << 'n';
- If the parsing did not succeed for any reason, we tell the user that the parsing did not go well. The cin stream object is now in a fail state and will not give us other input until we clear the fail state again. In order to be able to parse a new input afterward, we call cin.clear() and drop all input we received until now. The dropping is done with cin.ignore, where we specify that we are dropping the maximum number of characters until we finally see a newline character, which is also dropped. Everything after that is interesting input again:
} else {
cout << "Oh no, that did not go well!n";
cin.clear();
cin.ignore(
std::numeric_limits<std::streamsize>::max(),
'n');
}
- Let's now ask for some other input. We let the user enter names. As names can consist multiple words separated by spaces, the space character is not a good separator any longer. Therefore, we use std::getline, which accepts a stream object, such as cin, a string reference where it will copy the input into, and a separating character. Let's choose comma (,) as the separating character. By not just using cin alone and by using cin >> ws as a stream parameter for getline instead, we can make cin drop any leading whitespace before any name. In every loop step, we print the current name, but if a name is empty, we drop out of the loop:
cout << "now please enter some "
"comma-separated names:n> ";
for (string s; getline(cin >> ws, s, ',');) {
if (s.empty()) { break; }
cout << "name: "" << s << ""n";
}
}
- Compiling and running the program leads to the following output, in which we assumingly entered only valid inputs. The numbers are "1 2", which are parsed correctly, and then we enter some names which are then also listed correctly. An empty name input in the form of two consecutive commas quits the loop:
$ ./strings_from_user_input
Please Enter two numbers:
> 1 2
You entered: 1 and 2
now please enter some comma-separated names:
> john doe, ellen ripley, alice, chuck norris,,
name: "john doe"
name: "ellen ripley"
name: "alice"
name: "chuck norris"
- When running the program again, while entering bad numbers in the beginning, we see that the program correctly takes the other branch, drops the bad input and correctly continues with the name listening. Play around with the cin.clear() and cin.ignore(...) lines to see how that tampers with the name reading code:
$ ./strings_from_user_input
Please Enter two numbers:
> a b
Oh no, that did not go well!
now please enter some comma-separated names:
> bud spencer, terence hill,,
name: "bud spencer"
name: "terence hill"