How to Limit Input to Numbers Only - c++

I recently created a program that will create a math problem based on the user input. By entering either 1-4 the program can generate a problem or the user can quit by entering 5. The only problem I am having is that when I enter a character the program goes into an infinite loop. What function could I use to check if the input is not a number so I can display an error message?
//CIS180 Assignment #4
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
//Declare variables.
int num1, num2, menuNum;
int addInput, subInput, multInput, divInput;
int addAnswer, subAnswer, multAnswer, divAnswer;
int addSolution, subSolution, multSolution, divSolution;
srand(time(0));
//Display menu.
cout << "Menu" << endl;
cout << "1. Addition problem" << endl;
cout << "2. Subtraction problem" << endl;
cout << "3. Multiplication problem" << endl;
cout << "4. Division problem" << endl;
cout << "5. Quit this program" << endl << endl;
cout << "Enter your choice (1-5): " << endl;
cin >> menuNum;
//Loop that will provide math problems when user inputs number.
while(menuNum != 5)
{
//Check if the input is valid.
while((menuNum < 1) || (menuNum >5))
{
cout << "The valid choices are 1, 2, 3 , 4, and 5. Please choose: " << endl;
cin >> menuNum;
}
//Generate two random numbers for addition and display output.
if(menuNum == 1)
{
num1 = rand()%500 + 1;
num2 = rand()%500 + 1;
addSolution = num1 + num2;
cout << setw(5) << right << num1 << endl;
cout << setw(2) << left << "+" << setw(3) << right << num2 << endl;
cout << setw(5) << fixed << "-----" << endl;
cin >> addAnswer;
//Check if the addition answer input is correct.
if(addAnswer != addSolution)
cout << "Sorry, the correct answer is " << addSolution << "." << endl;
else if(addAnswer == addSolution)
cout << "Congratulations! That's right." << endl << endl;
}
.
.
.

First off, you should detect whether your input attempt was successful: always check after reading that the read attempt was successful. Next, when you identify that you couldn't read a value you'll need to reset the stream to a good state using clear() and you'll need to get rid of any bad characters, e.g., using ignore(). Given that the characters were typically entered, i.e., the user had to hit return before the characters were used it is generally reaonable to get of the entire line. For example:
for (choice = -1; !(1 <= choice && choice <= 5); ) {
if (!(std::cin >> choice)) {
std::cout << "invalid character was added (ignoring the line)\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
The use of std::numeric_limits<std::streamsize>::max() is the way to obtain the magic number which makes ignore() as many characters as necessary until a character with the value of its second argument is found.

Read a single character
If this character is a digit, use it.
If this character wasn't a digit, goto 1.
Actually, forget about step 2. Just check whether it was one of the digit characters you actually want ('1', '2', '3', '4', '5'):
char choice;
while(cin.get(choice)){
if(choice == '5')
break;
switch(choice){
default: printWrongCharacterMessage(); break;
case '1': do1Stuff(); break;
case '2': do2Stuff(); break;
case '3': do3Stuff(); break;
case '4': do4Stuff(); break;
}
}

You can use isdigit from ctype.h

Related

cin input not being accepted in while loop [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 11 months ago.
Improve this question
Hi I'm trying to use a cin input but on my second while loop, the inputs are not running though correctly. How would I go about this?
Here's what I have:
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
using std::endl;
using std::cout;
using std::cin;
using namespace std;
int a, A;
int main() {
int choice, num;
cout << "State Search" << endl;
cout << "" << endl;
cout << "1. Enter the first letter of your desired state" << endl;
cout << "2. Press 2 to Quit" << endl;
cout << "" << endl;
bool done = false;
while(!done) {
//user inputs desired choice
cin >> choice;
if(choice == a || choice == A)
{
cout << "Which State? (enter a number)" << endl;
cout << "1. Alabama" << endl;
cout << "2. Alaska" << endl;
cout << "3. Arizona" << endl;
cout << "" << endl;
while (!(cin >> num))
{
if(num == 1)
{
cout << "test output 1" << endl;
}
else if (num == 2)
{
cout << "test output 2" << endl;
}
else if (num == 3)
{
cout << "test output 3" << endl;
}
} break;
} break;
}
return 0;
}
Once the user chooses one of the above states using a number I want to display the chosen output.
Here is a cleaned up version of what you are trying to do with some inline comment where you were going wrong.
// You only need to include iostream in your example program
// Only include what you need
#include <iostream>
#include <limits>
// You do not need to include all of the std namespace in the local scope
// if you are using the things you want.
using std::endl;
using std::cout;
using std::cin;
using std::streamsize;
int main()
{
cout << "State Search\n\n";
cout << "1. Enter the first letter of your desired state\n";
cout << "2. Press 2 to Quit\n" << endl;
// Removed all the while(!done) / break; as it is just noise in the current iteration of your program.
// if you use an int for the choice variable, you will actually try to parse the input
// as an integer and return 0 if the user inputs 'a'
// you need to use a char for what you want to do
char choice;
cin >> choice;
// Also your a and A int value do not make sense as they are init to 0
// (global initialization), I guess what you want to do is compare to the char 'a' or 'A'. You could also transform the input to lowercase and compare only to 'a'.
if (choice == 'a' || choice == 'A')
{
// Use \n not std::endl as it will flush the output buffer
// all the time. std::endl is a false friend, use it only
// when you want to present your text to the user.
cout << "Which State? (enter a number)\n";
cout << "1. Alabama\n";
cout << "2. Alaska\n";
cout << "3. Arizona\n" << endl;
// We want to wait until we get a correct input and _then_
// do something with our input.
int num;
while (!(cin >> num))
{
// You might want to say something to your user if he doesn't input a correct number here.
// This will succeed if the user inputs 4, so you might also want to handle that case differently and ask the user to retry too in that case.
// The stream is now in error, you need to reset the state of the stream by clearing the error and emptying the buffer.
cin.clear();
cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
}
// Just showing another way of doing the if / else if dance in C/C++.
switch(num)
{
case 1: cout << "You chose Alabama" << endl; break;
case 2: cout << "You chose Alaska" << endl; break;
case 3: cout << "You chose Arizona" << endl; break;
default: cout << "I do not recognize the State" << endl; break;
}
}
// if we didn't receive 'a' or 'A' we just quit the program.
return 0;
}

Correct input went into validation loop at least once after return from sub menu

I'm current writing a simple application that involve certain menu driven, such as Main Menu > Sub-menu > sub-sub-menu.. etc.
And I put input validation on all of them to prevent input error like,
while (option != '1' && option != '2' && option != '3' && option != '0')
{
//correction prompt
}
In one of my menu, when I enter its sub-menu, and return back to it. Any input that I attempt to enter will result the system went into my validation loop at least once, given the input is appropriate or not.
My Code:
void passengerRecord()
{
int again = 0;
char option;
do
{
system("CLS");
cout << "Please tell me what you want to do." << endl;
cout << "1. Add Passenger Record" << endl;
cout << "2. Edit Passenger Record" << endl;
cout << "3. Delete Passenger Record" << endl;
cout << "0. Back to System Module Menu" << endl;
cout << "Your choice: ";
cin.ignore();
if (again > 0)
cin.clear();
cin.get(option);
while (option != '1' && option != '2' && option != '3' && option != '0')
{
system("CLS");
cout << "Error Input! Please try again." << endl;
cout << "Please tell me what you want to do." << endl;
cout << "1. Add Passenger Record" << endl;
cout << "2. Edit Passenger Record" << endl;
cout << "3. Delete Passenger Record" << endl;
cout << "0. Back to System Module Menu" << endl;
cout << "Your choice: ";
cin.get(option);
}
switch (option)
{
case '1': passengerAddsa();break;
case '2': passengerEditsa();break;
case '3': passengerDeletesa();break;
case '0': cout << "Redirecting back to module menu...";
cin.ignore();break;
default: cout << "Exception error occurred!";
}
again++;
} while (option != '0');
}
As long as I've enter one of its sub-menu (add,edit,delete), and return to here (either the other function using cin.get() and proceed to return;, or end of function), the next input I enter for this menu will goes into validation loop at least once.
This situation only occurred at second time ++ access to this menu, first time access has no problem
Method that I've tried:
1.) cin.ignore(), its useless and just required me to input more line.
2.) cin.clear(), I see no difference. Probably it has nothing to do with cin buffer
3.) Only run 1,2 method after second time at menu, with again ++ and if (again>0) //syntax, not helping as well.
I've squeezed what I've learned before but no luck, can't find similar problem.
Any help would be appreciated, thank you.
Problem Solve by running cin.ignore() only when first time access
void passengerRecord()
{
int again = 0;
char option;
do
{
//menu syntax
//.
//.
if (again == 0) // only run when it's first time access during this call
cin.ignore();
while (option != '1' && option != '2' && option != '3' && option != '0')
{
//error input correction
}
//proceed to sub-menu
again++; // increment or again = 1; to indicate the menu had been accessed during this call
} while (option != '0');
}
Hmm, the only certainty is: if you use cin prior to calling get(), you may need to flush the buffer and clear the flags (example below):
#include<iostream>
#include <vector>
using namespace std;
void passengerRecord(){
char option;
//Uncomment the below if cin was use prior to this function and not safely emptied.
//cin.ignore(INT_MAX, '\n');//Ignore with delimiter newline
//cin.clear();//Clear flags in cin
do
{
//system("CLS");//Commented to display data;
cout << "Please tell me what you want to do." << endl;
cout << "1. Add Passenger Record" << endl;
cout << "2. Edit Passenger Record" << endl;
cout << "3. Delete Passenger Record" << endl;
cout << "0. Back to System Module Menu" << endl;
cout << "Your choice: ";
cin.get(option);
cin.ignore(INT_MAX, '\n');//Ignore with delimiter newline
cin.clear();//Clear flags in cin
while (option != '1' && option != '2' && option != '3' && option != '0')
{
system("CLS");
cout << "Error Input! Please try again." << endl;
cout << "Please tell me what you want to do." << endl;
cout << "1. Add Passenger Record" << endl;
cout << "2. Edit Passenger Record" << endl;
cout << "3. Delete Passenger Record" << endl;
cout << "0. Back to System Module Menu" << endl;
cout << "Your choice: ";
cin.get(option);
cin.ignore(INT_MAX, '\n');//Ignore with delimiter newline
cin.clear();//Clear flags in cin
}
switch (option)
{
case '1':
cout << "passengerAddsa();" << endl;
break;
case '2':
cout << "passengerEditsa();" << endl;
break;
case '3':
cout << "passengerDeletesa();" << endl;
break;
case '0':
cout << "Redirecting back to module menu...";
cin.ignore(INT_MAX, '\n');//Ignore with delimiter newline
cin.clear();//Clear flags in cin
break;
default:
cout << "Exception error occurred!";
}
} while (option != '0');
}
int main() {
passengerRecord();
return 0;
}

Simple calculator issues (Not outputting answers)

just started reading a C++ book and one of the practice problems was to write a small calculator that takes as input one of the four arithmetic operations, the two arguments to those operations, and then prints out the results.
Sadly, the program works up until the user inputs the arithmetic option.
So if I chose to do multiplication, id write "Multiplication" and it was just stay there and not do anything after.
Image of the problem im having
#include <iostream>
#include <string>
using namespace std;
int main(){
// Simple calculator program
// Declaring three variables
float numberOne;
float numberTwo;
string operationOption;
// Asking the user which two numbers he/she will use
cout << "Enter the first number you would like to apply a arithmetic operation to: ";
cin >> numberOne;
cin.ignore();
cout << "Now enter the second number: ";
cin >> numberTwo;
cin.ignore();
// Using cin to input users selection
cout << "Enter the operation you want to perform." << endl;
cout << "The options you have are: " << endl;
cout << "Multiplication, Subraction, Division and Addition: " << endl;
cin >> operationOption;
cin.ignore();
cin.get();
// Where it all happens
if ( operationOption == "Multiplication" ) {
cout << "The first number multiplied by the second number is: " << numberOne * numberTwo << endl;
} else if ( operationOption == "Division" ) {
cout << "The first number divided by the second number is: " << numberOne / numberTwo << endl;
} else if ( operationOption == "Subtraction" ) {
cout << "The first number subtracted by the second number is: " << numberOne - numberTwo << endl;
} else if ( operationOption == "Addition ") {
cout << "The first number added to the second number is: " << numberOne + numberTwo << endl;
} else {
cout << "You entered an invalid option.";
};
}
Remove line :
cin.get();
will solve your problem

C++ error with input validation in a do-while loop

I'm creating a very simple number guessing game for a school project and am having trouble with the repeating main menu. I created it using a do-while loop and the problem I'm having is that the menu selection variable is an int, and so when I (or the user) enters a non-int input by accident when selecting from the menu the }while(condition) at the end of the main loop can't catch it and the program repeats infinitely. Conversely if you enter an invalid int at menu selection the program catches it displays the "invalid input" message and then repeats the main menu.
It's kind of hard to explain in writing exactly what I mean so here is the source code with relevant lines denoted with an asterisk. I'm saving as .cpp and am compiling in linux using g++ -ansi -pedantic -Wall -Werror The teacher has forbidden hardcoding in conditional statements hence the global constants.
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
const int PLAY = 1, HIGH_SCORE = 2, EXIT = 3;
const char YES = 'y', NO = 'n';
int main()
{
// Randomly generated value
int randomNumber;
// User input
int userGuess, menuChoice;
char repeat;
// Calculated value
int numberOfGuesses;
// Place-holder values (to be replaced by calculated values)
int score1 = 1000, score2 = 2000, score3 = 3000;
cout << endl << endl;
cout << "Greetings! This is a number guessing game where I think of" << endl
<< "a whole number between one and ten and you try to guess it!" << endl
<< "You can guess as many times as you like, so don't be afraid" << endl
<< "to use trial and error, but your score is based on the " << endl
<< "number of guesses you make (the lower the better) so don't " << endl
<< "guess too haphazardly. Remember, only guess whole numbers!" << endl
<< endl;
do
{
cout << endl << "Main menu." << endl
<< "1. Play game" << endl
<< "2. Display high scores" << endl
<< "3. Exit game" << endl
<< "Please select an option: ";
cin >> menuChoice;
if (cin.fail()){
cout << "Please enter a valid choice" << endl;
continue;
}
cin.ignore();
switch(menuChoice)
{
case PLAY:
do
{
unsigned seed = time(0);
srand(seed);
randomNumber = 1 + rand() % 10;
cout << endl << "Press enter when you're ready to begin!";
cin.ignore();
cout << "Ok I thought of one!" << endl << endl;
numberOfGuesses = 0;
do
{
numberOfGuesses++;
cout << "Enter your guess: ";
cin >> userGuess;
cin.ignore();
// Check user's guess
if (userGuess == randomNumber)
cout << "Correct! That was impressive!" << endl << endl;
else if (userGuess < randomNumber)
cout << "Not quite, you guessed low." << endl << endl;
else if (userGuess > randomNumber)
cout << "Not quite, you guessed high." << endl << endl;
}while (userGuess != randomNumber);
cout << "Your score for this game was " << numberOfGuesses << endl;
// Determine if a high score was beaten
if (numberOfGuesses <= score1)
{
score3 = score2;
score2 = score1;
score1 = numberOfGuesses;
cout << "That's a new all time high score!" << endl;
}
else if (numberOfGuesses <= score2)
{
score3 = score2;
score2 = numberOfGuesses;
cout << "That's a new high score!" << endl;
}
else if (numberOfGuesses <= score3)
{
score3 = numberOfGuesses;
cout << "That's a new high score!" << endl;
}
else
{
cout << endl;
}
cout << "Would you like to play again? y/n: ";
cin.get(repeat);
cin.ignore();
while (tolower(repeat) != YES && tolower(repeat) != NO)
{
cout << endl;
cout << "Sorry, that is an invalid choice." << endl
<< "Please enter 'y' for yes or 'n' for no: ";
cin.get(repeat);
cin.ignore();
}
}while (tolower(repeat) == YES);
break;
case HIGH_SCORE:
cout << endl << "High Score 1: " << score1 << endl
<< "High Score 2: " << score2 << endl
<< "High Score 3: " << score3 << endl << endl;
cout << "Press enter to continue. ";
cin.ignore();
break;
case EXIT:
cout << endl << "Thanks for playing, I'll see you next time!" << endl << endl;
break;
default:
cout << endl << "That is an invalid selection, please enter '1', '2' or '3'"
<< endl;
break;
}
}while (menuChoice != EXIT);
return 0;
}
Code Edited in regards to current answer.
Please let me know if you need anymore information, thanks in advanced!
Use cin.fail() like this (instead of just cin >> menuChoice;) (modelled after this post):
cin >> menuChoice;
if (cin.fail()) {
cout << "Please enter a valid choice" << endl;
cin.clear();
cin.ignore();
continue;
}
//Remove the cin.ignore() at this place!
For more detailed info, see this SO thread
Use a do-while to ensure that the loop body will run at least once.
By using a do-while and prompting a user outside the loop you assume the user wants to play the game once which may not be the case.
A cleaner approach IMO would be use a while loop. Display the menu outside the loop and at the end of the loop. The user will have the choice to exit immediately.
cout << "Greetings.....
cout << menu
// Get menuChoice input here.
while(menuChoice != EXIT){
...
cout << menu //reprompt at end to continue or exit cleanly
// Get menuChoice input here
}
Input Validation is a perfect time to use a do-while
do{
if(!cin){
cout << "Invalid input"
cin.clear()
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}while(!(cin >> menuChoice)) // This gets console input. If fail, loop.
Use numeric_limits<streamsize>::max() to completely clear the
buffer.
Use cin.clear() to reset the fail flag on cin so it wont
always be false.
cin.fail() is fine. However some would consider !cin more natural.

using cin.ignore()? Not sure how to make it work

bool showMenu(romanType roman){
cout << endl;
cout << "Just enter a number to choose an option" << endl;
cout << "1: Print the Roman Numeral" << endl;
cout << "2: Print the decimal value" << endl;
cout << "3: Enter a new Roman Numeral" << endl;
cout << "4: Quit the program" << endl;
cout << endl;
while (true) {
cout << "Your choice:" << endl;
int input;
cin >> input;
if (input == 1) {
cout << roman.getRomanString() << endl;
} else if(input ==2) {
cout << roman.getDecimalValue() << endl;
} else if(input == 3) {
return true;
} else if(input == 4) {
return false;
} else {
cout << "Invalid selection, please make a valid selection." << endl;
}
}
}
Alight, so by and large this works fine, I'm just having one small problem with my final else statement. As long as the user has entered a type of int, the loop does what it is supposed to, however if any kind of string is entered (i.e. 45r, rts, 3e5) the loop stops taking user input and just spirals infinitely, cout(ing) Invalid selection... and Your choice... over and over again. I think I need to use .ignore() to drop the \n in the case of a string, but I'm not sure of how to do that. Am I on the right track?
Yes, you're on the right track.
cin >> input tries to extract an integer. If this fails no symbols are extracted from cin and the failbit is set. In this case the extraction won't work anymore. You have to ignore the rest of the user input and clear the error bits:
} else {
cout << "Invalid selection, please make a valid selection." << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
// numeric_limits<streamsize>::max() returns the maximum size a stream can have,
// see also http://www.cplusplus.com/reference/std/limits/numeric_limits/
}
See also Why is this cin reading jammed?.