I'm giving a while statement two conditions but it doesn't appear to be working as I want it to.
cout << "Enter S if you booked a single room or D for a double room and press enter." << endl;
cin >> rtype;
while(rtype !='S' && rtype !='D')
{
cout << "That is not a valid room type, please try again." << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin >> rtype;
}
If I input "Sfbav", it takes the input as valid because the first character is 'S' and ignores that there are other characters there that would make it an invalid input.
How can I change this so that the input has to only be 'S' or 'D' to be treated as correct?
Option 1
Read the token as a string and compare it to "S" and "D".
std::string rtype;
cin >> rtype;
while(rtype != "S" && rtype != "D" )
{
cout << "That is not a valid room type, please try again." << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin >> rtype;
}
Option 2
Read the entire line as a string and compare it to "S" and "D".
std::string rtype;
getline(cin, rtype);
while(rtype != "S" && rtype != "D" )
{
cout << "That is not a valid room type, please try again." << endl;
getline(cin, rtype);
}
You can get the whole line, and check how many characters it has. If it has more than 1, then you know that the user entered Sfbav or something else.
while (true) {
std::string line; // stores the whole input that the user entered
std::getline(std::cin, line); // get the whole input
if (line.size() != 1) // if it does not have exactly 1 character, than it is invalid
std::cout << "That is not a valid room type, please try again.\n";
else { // if it has only 1 character, everything is ok
rtype = line.front();
break;
}
}
if your rtype is char
In this case I prefer to use std::setw( 1 ) to avoid getting more than one char, like:
char rtype;
std::cin >> std::setw( 1 ) >> rtype; // Sabc
std::cout << rtype << '\n'; // S
and:
#include <iomanip>
Related
My code is mostly working except for one minor issue. While it should only accept ints, it also accepts user input that start with an int, such as 6abc for example. I saw a fix for this here, but it changed the input type to string and added a lot more lines of code. I'm wondering if there's an easier way to fix this:
int ID;
cout << "Student ID: ";
// error check for integer IDs
while( !( cin >> ID )) {
cout << "Must input an integer ID." << endl ;
cin.clear() ;
cin.ignore( 123, '\n' ) ;
}
In a word - no.
But what you can do is instead read a whole word into a std::string first, and then convert that entire word into an int, checking for errors in that conversion, eg:
int ID;
string input;
do
{
cout << "Student ID: ";
if (!(cin >> input))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
else
{
size_t pos = 0;
try
{
ID = stoi(input, &pos);
if (pos == input.size())
break;
}
catch (const std::exception &) {}
}
cout << "Must input an integer ID." << endl;
}
while (true);
Live Demo
I found this similar question being asked so many times but I still couldn't find a solution for mine.
In my case, I want to display something when the user enters a number from 1 - 5, give an error when he inputs something wrong like characters, "3g", "3.", "b3" and any float number.
I tried the code below, but it created so many other problems. Like if I enter 3g or 3.5, it'll only take the 3 and ignore the rest so the (!cin) doesn't work at all.
Second, if I input something like a character, the __userChoice will be automatically converted into 0 and the program prints out "Please select a number from 1 to 5." instead of "Invalid input, please input an integer number.\n", which is what I want.
cout << "Please select: ";
cin >> __userChoice;
if (__userChoice > 0 && __userChoice < 5) {
cout << "You select menu item " << __userChoice <<". Processing... Done!\n";
}
else if (__userChoice == 5) {
Finalization(); //call exit
}
else if (__userChoice <= 0 || __userChoice > 5) {
cout << "Please select a number from 1 to 5.\n";
}
else (!cin) {
cout << "Invalid input, please input an integer number.\n";
}
cin.clear();
cin.ignore(10000, '\n');
operator>> is not guaranteed to output a meaningful integer value if a failure occurs, but you are not checking for failure before evaluating __userChoice, and the way your ifs are structured the else (!cin) check will never be reached. But even if operator>> is successful, you are not checking if the user entered more than just an integer.
To do what you are asking for, you should read from std::cin into a std::string first using std::getline(), and then use std::istringstream or std:stoi() (or equivilent) to convert the string to an int with error checking.
For example:
bool strToInt(const std::string &s, int &value)
{
std::istringstream iss(s);
return (iss >> value) && iss.eof();
// Or:
std::size_t pos;
try {
value = std::stoi(input, &pos);
}
catch (const std::exception &) {
return false;
}
return (pos == input.size());
}
...
std::string input;
int userChoice;
std::cout << "Please select: ";
std::getline(std::cin, input);
if (strToInt(input, userChoice))
{
if (userChoice > 0 && userChoice < 5)
{
std::cout << "You selected menu item " << userChoice <<". Processing... Done!\n";
}
else if (userChoice == 5)
{
Finalization(); //call exit
}
else
{
std::cout << "Please select a number from 1 to 5.\n";
}
}
else
{
std::cout << "Invalid input, please input an integer number.\n";
}
Just to make clear, I am very new to C++.
But I wrote I very small program to test my skill with arrays and ran into a problem with cin.
If the user enters number, like the program expects them to, all is well. But if a string gets entered, all input is skipped and the program ends.
I set up all of my inputs like this: cin >> x;cin.clear();cin.ignore();
So what is awry??
Here is the full code:
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
system("cls");
int create = 1;
int entry;
int x;
string chc;
cout << "How long should the array be?" << endl;
cout << ":";
cin >> x;cin.clear();cin.ignore();
if(x<1){x=1;}
int myArray[x];
string askcontinue;
for(int x=0;x<sizeof(myArray)/sizeof(myArray[0]);x++){
system("cls");
cout << "Enter value #" << x+1 << endl;
cout << ":";
cin >> entry;cin.clear();cin.ignore();
myArray[x]=entry;
}
system("cls");
cout << "Index - Value" << endl;
for(int x=0;x<sizeof(myArray)/sizeof(myArray[0]);x++){
cout << x << " ------ " << myArray[x] <<endl;
}
system("cls");
cout << "Restart? [Y/N]" << endl;
cout << ":";
cin >> chc;cin.clear();cin.ignore();
if(chc=="y" || chc=="Y"){main();}
}
cin >> x;cin.clear();cin.ignore();
This thing that you're doing throughout your program is part of the problem. If the user enters something that doesn't meet the formatting requirements for an integer, the stream goes into a failure state. Directly after that happens you clear the stream and discard the next character. If the user entered in more than one character as part of the invalid input, the ignore() call is simply discarding the next character, but not all of the invalid input.
You need to check if the input did not succeed, and then discard the input using the overload of ignore() that takes the number of characters you wish to discard. Do the following if you wish to consistently ask the user for input if he does not provide valid characters:
while (!(std::cin >> x)) {
std::cout << "How long should the array be?" << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
But judging from your code, it doesn't look like you want to repeatedly ask the user for input. In that case, you should check for valid input instead and do nothing in the invalid case:
if (std::cin >> x) {
...
}
Also, VLAs (or variable-length arrays) are a non-standard feature of C++, provided as extentions in some compilers. Don't use them. Instead, allocate dynamically by using std::vector:
std::vector<int> myArray(x);
NOTE: you should also change the fact that you defining the variable 'x' three times
the problem you are having, is that c input does not type checking, so it does not care what was entered, so this is up to you. You should input everything as a string, and then make sure that the string contains nothing but numbers, THEN you can use std::stoi, or whatever the appropriate conversion method is. if they DO NOT enter a valid number, then you can just say INVALID, and tell the user to enter a valid number, and go back to the input, you could use something such as:
system("cls");
cout << "Enter value #" << x + 1 << endl;
cout << ":";
cin >> entry; cin.clear(); cin.ignore();
while(!is_valid_integer(entry))
{
system("cls");
cout << "INVALID NUMBER \n Enter value #" << x + 1 << endl;
cout << ":";
cin >> entry; cin.clear(); cin.ignore();
}
myArray[x] = std::stoi(entry);
And then entry is a string.
is_valid_integerwould be defined as:
bool is_valid_integer(std::string str)
{
for(auto it : str)
{
if(!(ch == '0' || ch == '1' || ch == '2' || ch == '3' || ch == '4' || ch == '5' || ch == '6' || ch == '7' || ch == '8' || ch == '9'))
return false;
//OR: this is more efficient, but is reliant on using ascii codes (which in this case we are)
//if(!(ch >=48 && ch <= 57)) return false;
}
return true;//all numbers
}
If the input is an integer, I want to set it equal to an integer variable.
If the input is a string, I will want to set it to a string variable, and later check if the string is "quit".
I don't know how to check it. I've looked for a built in function and found nothing.
while (true) {
int numberEntered;
string stringEntered;
cout << "enter a number to see if it is greater than 5: \n or enter \'quit\' to exit the program";
//I don't know what to do below here
cin >> ;
if (stringEntered == "quit") {
break;
}
if (numberEntered > 5) {
cout << "that number is greater than 5" << endl;
}
else {
cout << "not greater than 5" << endl;
}
}
cin >> numberEntered;
if (!cin.fail())
{
...
It may be more idiomatic to use:
if (cin >> numberEntered)
David S.'s answer is good. If you want to tidily handle garbage being entered after the line, here is another option (this is more complicated for your situation, but if you later want to expand your program to handle a lot of different input, then this way may come out to be simpler).
while( true )
{
string stringEntered;
cout << "enter a number to see if it is greater than 5: \n or enter \'quit\' to exit the program: " << flush;
// read the whole line, this ensures no garbage remains in the input stream
getline(cin, stringEntered);
if ( stringEntered == "quit" )
break;
// this checks that a number was entered and nothing else
istringstream iss(stringEntered);
int numberEntered;
char ch;
if ( !(iss >> numberEntered) || (iss >> ch) )
{
cout << "please try again. ";
continue;
}
// process the number
cout << "that number is " << (numberEntered > 5 ? "" : "not ")
<< "greater than 5." << endl;
}
You may need #include <sstream>.
I am trying to make a cin where the user can only enter 0 to 1. If the user doesnt enter those numbers then he should get an error saying "Please enter within the range of 0 to 1."
But its not working.
What am i doing wrong?
int alphaval = -1;
do
{
std::cout << "Enter Alpha between [0, 1]: ";
while (!(std::cin >> alphaval)) // while the input is invalid
{
std::cin.clear(); // clear the fail bit
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore the invalid entry
std::cout << "Invalid Entry! Please Enter a valid value: ";
}
}
while (0 > alphaval || 1 < alphaval);
Alpha = alphaval;
Try this:
int alphaval;
cout << "Enter a number between 0 and 1: ";
cin >> alphaval;
while (alphaval < 0 || alphaval > 1)
{
cout << "Invalid entry! Please enter a valid value: ";
cin >> alphaval;
}
If you want to trap empty lines I'd use std::getline and then parse the string to see if the input is valid.
Something like this:
#include <iostream>
#include <sstream>
#include <string>
int main()
{
int alphaval = -1;
for(;;)
{
std::cout << "Enter Alpha between [0, 1]: ";
std::string line;
std::getline(std::cin, line);
if(!line.empty())
{
std::stringstream s(line);
//If an int was parsed, the stream is now empty, and it fits the range break out of the loop.
if(s >> alphaval && s.eof() && (alphaval >= 0 && alphaval <= 1))
{
break;
}
}
std::cout << "Invalid Entry!\n";
}
std::cout << "Alpha = " << alphaval << "\n";
return 0;
}
If you want a different prompt on error then I'd put the initial prompt outside the loop and change the inner prompt to what you prefer.
Week one of C++, starting with Peggy Fisher's Learning C++ on Lynda.com.
This is what I came up with. Love to receive feedback.
int GetIntFromRange(int lower, int upper){
//variable that we'll assign input to
int input;
//clear any previous inputs so that we don't take anything from previous lines
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
//First error catch. If it's not an integer, don't even let it get to bounds control
while(!(cin>>input)) {
cout << "Wrong Input Type. Please try again.\n";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
//Bounds control
while(input < lower || input > upper) {
cout << "Out of Range. Re-enter option: ";
cin.ignore(numeric_limits<streamsize>::max(), '\n');
//Second error catch. If out of range integer was entered, and then a non-integer this second one shall catch it
while(!(cin>>input)) {
cout << "Wrong Input Type. Please try again.\n";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
//return the cin input
return input;
}
As the exercise was to order Hamburgers, this is how I ask for the amount:
int main(){
amount=GetIntFromRange(0,20);
}