I am prompting the user to enter an integer value. When the value is incorrect, the program works. However, when the user enters an integer input, the user needs to enter the input twice.
I looked at other tutorials on how to use the while loop to catch erroneous input, and that part worked for me. However, the integer values need to be entered twice in order for the program to run.
#include <iostream>
using namespace std;
int main() {
cout << "*************************************************" << endl;
cout << "******************|DVD Library|******************" << endl;
cout << "*************************************************" << endl;
cout << "1.\tAdd DVD" << endl;
cout << "2.\tDelete DVD" << endl;
cout << "3.\tSearch DVD" << endl;
cout << "4.\tList All DVDs in the Library" << endl;
cout << "5.\tAdd DVD to Favorites List" << endl;
cout << "6.\tDelete DVD from Favorites List" << endl;
cout << "7.\tSearch DVD in Favorites List" << endl;
cout << "8.\tList All DVDs in Favorites List" << endl;
cout << "9.\tQuit" << endl;
cout << "*************************************************" << endl;
int input;
cin >> input;
while (!(cin >> input)) {
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Please enter an integer --> " << flush;
}
if (input < 1 || input > 9) {
cout << "Invalid input! Please try again!" << endl;
}
return 0;
}
You ask for the input twice:
cin >> input;
while(!(cin >> input )){
Removing the first line might make it work you intended.
'The user has to enter the input twice' Look at your code
int input;
cin >> input;
while(!(cin >> input )){
How many times do you ask the user for input?
You'd have more luck with this
int input;
while(!(cin >> input )){
Your error recovery code looks reasonable, haven't tested it though.
int input;
while (cout << "Your choice: ",
!(cin >> input) || input < 1 || 9 < input)
{
cin.clear();
while (cin.get() != '\n');
cerr << "Invalid input! Please try again!\n";
}
Thanks everyone! The "cin >> input;" line was unnecessary. At first, I left it there because it would actually tell the user the error message if the user entered a numeric input such as a double. So, if the user entered something like 3.3, the program would display an error message that I specified ("Please enter an integer" line). However, the program in this case (when there is a double) asks the user to prompt for the integer input twice and then continues the program. When I delete the said unnecessary line, the program accepts a double input, but what it does, it takes the numeric value before the decimal point and uses it as the integer. So, a value of 1.2 is recorded as 1 when I tested it. I'm unsure why this phenomenon happens, but the program works otherwise. Maybe it accounts for human error?
#include <iostream>
using namespace std;
int main() {
cout << "*************************************************" << endl;
cout << "******************|DVD Library|******************" << endl;
cout << "*************************************************" << endl;
cout << "1.\tAdd DVD" << endl;
cout << "2.\tDelete DVD" << endl;
cout << "3.\tSearch DVD" << endl;
cout << "4.\tList All DVDs in the Library" << endl;
cout << "5.\tAdd DVD to Favorites List" << endl;
cout << "6.\tDelete DVD from Favorites List" << endl;
cout << "7.\tSearch DVD in Favorites List" << endl;
cout << "8.\tList All DVDs in Favorites List" << endl;
cout << "9.\tQuit" << endl;
cout << "*************************************************" << endl;
int input;
while (!(cin >> input)) {
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Please enter an integer --> " << flush;
}
if (input < 1 || input > 9) {
cout << "Invalid input! Please try again!" << endl;
}
return 0;
}
Related
#include<iostream>
#include<ctime>
#include<cstdlib>
using namespace std;
int main(){
int gnumber, rnumber;
char choice;
int tries;
do {
cout << "Welcome to the Number Guessing Game!" << endl;
cout << endl; // breakline
cout << "How many tries: ";
cin >> tries;
cout << endl;
while (tries > 0){
srand(time(NULL));
rnumber = rand() % 99;
cout <<"Enter an integer greater than or equal to 0 and less than 100:";
cin >> gnumber;
system("cls");
if (tries != 1){
if (gnumber < 100 && gnumber >= 0){
if (gnumber == rnumber){
cout << "Congratulations! You've guessed the number." << endl;
tries--;
cout << "Remaining tries: " << tries << endl;
}
else if (gnumber > rnumber){
cout << "Your guess is higher than the number." << endl;
tries--;
cout << " Guess Again!" << endl;
cout << "Remaining tries: " << tries << endl;
}
else{
cout << "Your guess is lower than the number." << endl;
tries--;
cout << " Guess Again!" << endl;
cout << "Remaining tries: " << tries << endl;
}
}
else
cout << "Must greater or equal to 0 and lesser than 100!" << endl;
}
else
{
cout << "Game over!" <<" The number is: " << rnumber << endl;
cout << "Play Again? (Y/N)" << endl;
cin >> choice;
system("cls");
}
}
}while(choice == 'Y' || choice == 'y'); //
system("pause");
return 0;
}
EVEN IF I ENTER CHOICE AS 'N' OR 'n' IT WONT STOP THE LOOP.
And even if I enter 'Y' or 'y', it does not ask how many tries i wanted.
Instead it just asks directly what integer I would want to enter.
Please try to copy and compile the code to further understand what the problem is. Please help.
P.S.: This is a guessing program I'm making by the way...
the bug in your inner loop if the use enters a value other than one in else you don't decrement tries so it gets stuck:
else
{
cout << "Game over!" <<" The number is: " << rnumber << endl;
cout << "Play Again? (Y/N)" << endl;
cin >> choice;
system("cls");
tries--; // add this
}
Okay so as the title said its refusing to execute the stuff right under the "do" function even though as far as i can tell all the parameters for a repeat have been fulfilled. So far what i get when i run the program is something along the lines of...
"Would you like to search another name?
Please enter Y for yes and n for no:"
looping over and over when i press y
#include <iostream>
#include <string>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;
int main()
{
vector <string> vName, vID, vClass;
string sName, sID, sClass, sSearch, cQuestion;
int iSize, iStudent;
// Display initial vector size
iSize = vName.size();
cout << "Student list starts with the size:" << iSize << endl;
// Get size of list from user
cout << "How many students would you like to add?" << endl;
cin >> iStudent;
cin.ignore();
// Get names, ids, and classes
for (int i = 0; i < iStudent; i++)
{
cout << "Student" << i + 1 << ":\n";
cout << "Please enter the student name: ";
getline(cin, sName);
vName.push_back(sName);
cout << "Enter ID number ";
getline(cin, sID);
vID.push_back(sID);
cout << "Enter class name ";
getline(cin, sClass);
vClass.push_back(sClass);
}
// Display header
cout << "The list of students has the size of: " << iStudent << endl;
cout << "The Student List" << endl;
cout << "\n";
cout << "Name:" << setw(30) << "ID:" << setw(38) << "Enrolled Class : " << endl;
cout << "--------------------------------------------------------------------------";
cout << "\n";
// for loop for displying list
for (int x = 0; x < vName.size() && vID.size() && vClass.size(); x++)
{
cout << vName[x] << "\t \t \t" << vID[x] << "\t \t \t" << vClass[x] << endl;
}
// Sorting function
cout << "\n";
cout << "The Student List after Sorting:" << endl;
cout << "\n";
sort(vName.begin(), vName.end());
for (int y = 0; y < vName.size(); y++)
{
cout << vName[y] << endl;
}
cout << "\n";
// Search function
do
{
cout << "Please Enter a name to be searched:" << endl;
getline(cin, sSearch);
if (binary_search(vName.begin(), vName.end(), sSearch))
{
cout << sSearch << " was found." << endl << endl;
}
else
{
cout << sSearch << " was not found." << endl << endl;
}
cout << "Would you like to search another name?" << endl << endl;
cout << "Please enter Y for Yes and N for No:" << endl << endl;
cin >> cQuestion;
} while (cQuestion == "Y" || cQuestion == "y");
cout << "Thank you for using this program!" << endl;
return 0;
}
Edit:
Posted whole program, please excuse any grammatical mistakes, I'm just trying to get the program down before i go in there and make it pretty.
The tail of your loop does this:
cout << "Please enter Y for Yes and N for No:" << endl << endl;
cin >> cQuestion;
which will consume your string if you entered one, but leave the trailing newline in the input stream. Thus when you return to the top of the loop after entering Y or y, and do this:
cout << "Please Enter a name to be searched:" << endl;
getline(cin, sSearch);
the getline will extract an empty line.
How to consume the unread newline from the input stream is up to you. You will likely just end up using .ignore() as you did prior in your program. Or use getline to consume cQuestion. You have options. Pick one that works.
And as a side note, I would strongly advise you check your stream operations for success before assuming they "just worked". That is a hard, but necessary, habit to break. Something like this:
do
{
cout << "Please Enter a name to be searched:" << endl;
if (!getline(cin, sSearch))
break;
if (binary_search(vName.begin(), vName.end(), sSearch))
{
cout << sSearch << " was found." << endl << endl;
}
else
{
cout << sSearch << " was not found." << endl << endl;
}
cout << "Would you like to search another name?" << endl << endl;
cout << "Please enter Y for Yes and N for No:" << endl << endl;
} while (getline(cin,cQuestion) && (cQuestion == "Y" || cQuestion == "y"));
If cQuestion is a char array then you need to use strcmp or stricmp to compare it with another string i.e. "Y" and "y" in this case. If cQuestion is a single char then you need to compare with 'Y' and 'y' (i.e. with a single quote)
Strings in C++ are not first class types therefore they do not have some of the string operation that exist for other basic types like ints and floats. You do have std::string as part of the standard C++ library which almost fulfills the void.
If you just change the type of cQuestion to std::string your code should work but if you want to stick with chars then you will need to change the quote style.
I am a very newbie programmer, so I don't really know much about writing code to protect the application.. Basically, I created a basicMath.h file and created a do while loop to make a very basic console calculator (only two floats are passed through the functions). I use a series of if and else if statements to determine what the users wants to do. (1.add, 2.subtract, 3.multiply, 4.divide) I used a else { cout << "invalid input" << endl;} to protect against any other values, but then I tried to actually write a letter, and the program entered a infinite loop. Is there anyway to protect against users who accidentally hit a character instead of a number?
`#include <iostream>
#include "basicMath.h"
using namespace std;
char tryAgain = 'y';
float numOne = 0, numTwo = 0;
int options = 0;
int main()
{
cout << "welcome to my calculator program." << endl;
cout << "This will be a basic calculator." << endl;
do{
cout << "What would you like to do?" << endl;
cout << "1. Addition." << endl;
cout << "2. Subtraction." << endl;
cout << "3. Multiplication" << endl;
cout << "4. Division." << endl;
cin >> options;
if (options == 1){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " + " << numTwo << " = " << add(numOne, numTwo) << endl;
}
else if (options == 2){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " - " << numTwo << " = " << subtract(numOne, numTwo) << endl;
}
else if (options == 3){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " * " << numTwo << " = " << multiply(numOne, numTwo) << endl;
}
else if (options == 4){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " / " << numTwo << " = " << divide(numOne, numTwo) << endl;
}
else {
cout << "Error, invalid option input." << endl;
}
cout << "Would you like to use this calculator again? (y/n)" << endl;
cin >> tryAgain;
}while (tryAgain == 'y');
cout << "Thank you for using my basic calculator!" << endl;
return 0;
}
`
One way would be to use exception handling, but as a newbie you're probably far from learning that.
Instead use the cin.fail() which returns 1 after a bad or unexpected input. Note that you need to clear the "bad" status using cin.clear().
A simple way would be to implement a function:
int GetNumber ()
{
int n;
cin >> n;
while (cin.fail())
{
cin.clear();
cin.ignore();
cout << "Not a valid number. Please reenter: ";
cin >> n;
}
return n;
}
Now in your main function wherever you are taking input, just call GetNumber and store the returned value in your variable. For example, instead of cin >> numOne;, do numOne = GetNumber();
When you input to cin, it is expecting a specific type, such as an integer. If it receives something that it does not expect, such as a letter, it sets a bad flag.
You can usually catch that by looking for fail, and if you find it, flush your input as well as the bad bit (using clear), and try again.
Read a whole line of text first, then convert the line of text to a number and handle any errors in the string-to-number conversion.
Reading a whole line of text from std::cin is done with the std::getline function (not to be confused with the stream's member function):
std::string line;
std::getline(std::cin, line);
if (!std::cin) {
// some catastrophic failure
}
String-to-number conversion is done with std::istringstream (pre-C++11) or with std::stoi (C++11). Here is the pre-C++11 version:
std::istringstream is(line);
int number = 0;
is >> number;
if (!is) {
// line is not a number, e.g. "abc" or "abc123", or the number is too big
// to fit in an int, e.g. "11111111111111111111111111111111111"
} else if (!is.eof()) {
// line is a number, but ends with a non-number, e.g. "123abc",
// whether that's an error depends on your requirements
} else {
// number is OK
}
And here the C++11 version:
try {
std::cout << std::stoi(line) << "\n";
} catch (std::exception const &exc) {
// line is not a number, e.g. "abc" or "abc123", or the number is too big
// to fit in an int, e.g. "11111111111111111111111111111111111"
std::cout << exc.what() << "\n";
}
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.
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?.