While statement won't stop - c++

I have a while statement that keeps repeating the text without giving the user a chance to input another value for action. What am I doing wrong? It still doesn't ask for input. I need for the code to display the text once, then ask for input. Presumably, if you typed anything but 1 it would repeat the sequence. But as it stands it simply kicks you out of the loop without the chance to correct the action (As of the last edit, see below.)
int action = 0;
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
cin >> action;
}
One suggestion was:
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
cin >> action;
cin.ignore();
}
That still produces text over and over.
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
if (!(cin >> action))
// ...problems in the I/O stream...
break;
}
This one kicks you out without a chance to input a new action.

If you type a character that is not white space and can't be part of an integer, then you have an infinite loop. Each attempt to input to action fails on the invalid character without changing the value stored in action.
You could write:
int action = 0;
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
if (!(cin >> action))
// ...problems in the I/O stream...
break;
}
This will handle EOF and alphabetic characters more gracefully than a continuous loop. You might need to set a flag or return an error condition from the function or do something else other than break out of the loop. Always check your inputs for success.
You might also consider outputting the value you're getting stored in action in the loop, so you can see what is happening:
int action = 0;
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
if (!(cin >> action))
// ...problems in the I/O stream...
break;
cerr << "Action: " << action << endl;
}
This might tell you something useful too.
Please show a complete little program that illustrates your problem — an SSCCE (Short, Self-Contained, Correct Example).
For example, I'm testing with:
#include <iostream>
using namespace std;
int main()
{
int action = 0;
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
if (!(cin >> action))
{
// ...problems in the I/O stream...
break;
}
cout << "Action: " << action << endl;
}
cout << "After loop" << endl;
if (!cin)
cout << "cin is bust" << endl;
else
cout << "Action: " << action << endl;
}
That's no longer minimal code — the material after the loop is merely telling me what is happening. But it does help me ensure that my code is doing what I expect.
What does your equivalent code look like, and what are you typing in response to the prompts — and especially, what are you typing before you get to this code fragment (and what other input activity is going on before you get here)?

Related

std::cin failure leading to looped if statement in while loop

So I figure I'll put this here since I had to traverse a lot of docs and forums to find the definitive answer. I was trying to get input from the user and check if the input was an integer using isdigit() in an if statement. If the if statement failed the program would output an error message. Although, when a nondigit character was entered the program would loop through the error message endlessly. Here's that code:
int guess = -1;
while (game.getCurQuestion() <= 4) {
std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
std::cin >> guess;
if(isdigit(guess))
{
game.guess(guess);
else
{
std::cout << "Error\n"; //this would be looped endlessly
}
}
std::cout << "You got " << game.getCorrect() << " correct" << std::endl;
return 0;
}
NOTE: Solved, only posted to include my solution. Feel free to correct if I stated anything incorrectly.
The posted way will fail sometimes and will cast the doubles to integers if any doubles are input.
Use something like the following
int getIntInput() {
try {
std::string input;
std::cout << "\nPlease Enter a valid Integer:\t";
std::cin >> input;
size_t takenChars;
int num = std::stoi(input, &takenChars);
if (takenChars == input.size()) return num;
} catch (...) {}
return getIntInput();
}
Problem: The program kept hold of the non-integer value stored in the cin buffer. This leads to the program never leaving the error message.
Solution:
Use std::cin.fail() to check if the input matches the variable data type. I.E. int was the expected input but the user entered a char. In this case std::cin.fail() would be true.
In the case of std::cin.fail(), use std::cin.clear() and std::cin.ignore(std::numeric_limits<int>::max(), 'n') std::cin.clear() will clear the error flag. The std::cin.ignore(std::numeric_limits<int>::max(), 'n') will ignore any other input that is not an integer and will skip to the new line. Effectively progressing the program.
The solution implemented in my code looks like this:
int guess = -1;
while (game.getCurQuestion() <= 4) {
std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
std::cin >> guess;
if (std::cin.fail())
{
std::cout << "Please enter a valid number\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
}
game.guess(guess);
}
Hope this helps and that it saves some people the tedious research because of never learning std::cin error handling! Note: I'm aware my implementation skips the current move, call it punishment ;)

How to limit user input in C++ for strings & characters?

I'm trying to create a small restaurant program in which I'll be practicing everything I learned in C++ so far. However I jumped into a small issue. At the beginning of the program, I prompt the user whether they want to enter the program, or leave it by choosing Y or N. If the input is anything other than that the program will tell the user is invalid.
The issue is lets say the user input one invalid character a.
The invalid output will be displayed normally and everything seems perfect.
But if the user inputs two characters, or more, the invalid output case will be printed as many as the characters input by the user. Sample below:
Output image
#include <iostream>
int main()
{
char ContinueAnswer;
std::string Employee {"Lara"};
std::cout << "\n\t\t\t---------------------------------------"
<< "\n\t\t\t| |"
<< "\n\t\t\t| Welcome to OP |"
<< "\n\t\t\t|Home to the best fast food in Orlando|"
<< "\n\t\t\t| |"
<< "\n\t\t\t--------------------------------------|" << std::endl;
do
{
std::cout << "\n\t\t\t Would you like to enter? (Y/N)"
<< "\n\t\t\t "; std::cin >> ContinueAnswer;
if(ContinueAnswer == 'y' || ContinueAnswer == 'Y')
{
system("cls");
std::cout << "\n\t\t\t My name is " << Employee << "."
<< "\n\t\t\tI will assist you as we go through the menu." << std::endl;
}
else if(ContinueAnswer == 'n' || ContinueAnswer == 'N')
{
std::cout << "\t\t\t\tGoodbye and come again!" << std::endl;
return 0;
}
else
std::cout << "\n\t\t\t\t Invalid Response" << std::endl;
}
while(ContinueAnswer != 'y' && ContinueAnswer != 'Y')
Thank you for taking time to read and for anyone who answers :)
You could simply make the user input a string:
std::string ContinueAnswer;
and compare like this:
if(ContinueAnswer == "y" || ContinueAnswer == "Y")
which will handle multi-character inputs.
If you want to handle spaces in the input as well, change the:
std::cin >> ContinueAnswer;
to:
std::getline(std::cin, ContinueAnswer);
Before addressing your question I need to point out that you should always verify that the input was successful before doing anything with it. Processing variables which were not set due to the inout failing is a rather common source of errors. For example:
if (std::cin >> ContinueAnswer) {
// do something with successfully read data
}
else {
// deal with the input failing, e.g., bail out
}
I assume you consider everything on the same line to be invalid if nine of the expected characters was read. You could read a line into an std::string. However, that could be abused to provide an extremely long line of input which would eventually crash your program. Also, reading data into a std::string just to throw it away seems ill-advised. I’d recommend ignoring all characters up to and including a newline which could be done using (you need to include <limits> for this approach):
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), ‘\n’);
The first argument is a special value indicating that there may be an arbitrary amount of character before the newline. In practice you could probably use a value like 1000 and it would be fine but it can be gamed. Of course, in a real application a dedicated limit may be used to prevent an adversary to keep the program busy for long. I tend to assume my programs are under attack to make sure I deal with unusual cases.
A quick refactor produces this:
#include <iostream>
#include <cstring>
#include <stdio.h>
int main()
{
char ContinueAnswer[256];
std::string Employee {"Lara"};
std::cout << "\n\t\t\t---------------------------------------"
<< "\n\t\t\t| |"
<< "\n\t\t\t| Welcome to OP |"
<< "\n\t\t\t|Home to the best fast food in Orlando|"
<< "\n\t\t\t| |"
<< "\n\t\t\t--------------------------------------|" << std::endl;
do
{
std::cout << "\n\t\t\t Would you like to enter? (Y/N)"
<< "\n\t\t\t "; std::cin.getline(ContinueAnswer,sizeof(ContinueAnswer));
if(strcmp(ContinueAnswer, "Y") == 0 || strcmp(ContinueAnswer, "y") == 0)
{
system("cls");
std::cout << "\n\t\t\t My name is " << Employee << "."
<< "\n\t\t\tI will assist you as we go through the menu." << std::endl;
}
else if(strcmp(ContinueAnswer, "N") == 0 || strcmp(ContinueAnswer, "n") == 0)
{
std::cout << "\t\t\t\tGoodbye and come again!" << std::endl;
return 0;
}
else
std::cout << "\n\t\t\t\t Invalid Response" << std::endl;
}
while(true);
}
The cin.getline will get all characters until a delimiter. Then, you can check for equivalence using strcmp and reject anything other than what you want. Lastly, it seems like you are wanting this to be in an infinite loop, so don't worry about checking the input at the end and just loop back.

Safe [Y/N]; [1/2/3/etc.] function

I tried to make a an introduction to a "game", and in its functions I made some Yes/No, 1/2/3, situations.
Im new to this however it wasn't that difficult, worked perfectly. The problem appeared when handling with invalid inputs. So this is what the code looks like by now:
#include "Introduction.h"
#include "GameConstants.h"
#include "PlayerCharacter.h"
#include <iostream>
#include <windows.h>
using namespace std;
Introduction::Introduction()
{
}
/////////Function N.1///////////
void Introduction::presentation()
{
char confirm;
string enteredName;
cout << constants.line() << "Welcome traveler! What is the name?" << endl;
getline(cin,enteredName);// Gets the WHOLE LINE as the name.
while (confirm != 'Y') //If the player doesn't confirm the name with 'Y' in will run again until it does.
{
cout << constants.xline() << "Your name is " << enteredName << " right? (Y/N)" << endl;
cin >> confirm; //The player's answer
cin.sync(); //Only takes the first character
confirm = toupper(confirm); //Turns player message into CAPS for easier detection in the "if" statements
if (confirm == 'N'){ //If not the correct name, gives another chance
cout << constants.xline() << "Please, tell me your name again..." << endl;
cin >> enteredName;
cin.sync();}
if ((confirm != 'Y')&&(confirm != 'N')){ //If an invalid input is entered, gives another chance. And insults you.
cout << constants.xline() << "Fool Go ahead, just enter your name again." << endl;
cin >> enteredName;
cin.sync();}
}
if (confirm == 'Y'){ //When the answer is yes ('Y') /* Uneeded line */
PC.setName(enteredName); //Saves the name
cout << constants.xline() << "Excellent! I have a few more questions for you " << PC.name() << "..." << endl;
}
}
//////////Function N.2///////////
void Introduction::difSelection(){
int selectedDif = 0; //Variable to store selected difficulty whitin this function.
Sleep(2500);
cout << constants.xline() << "What kind of adventure do you want to take part in?" << endl;
Sleep(2500); //Wait 2,5 s
cout << "\n1= Easy\n2= Normal\n3= Hard" << endl;
while(selectedDif != 1&&2&&3){ //Selected option must be 1/2/3 or will run again
cin >> selectedDif; //Sets the user selected difficulty
cin.sync(); //Gets only first character
if((selectedDif != 1||2||3)&&(!(selectedDif))){ //If the input isn't 1/2/3 AND is an invalid character, this will run. And it'll start again
cout << constants.xline() << "Criminal scum. Go again." << endl;
cin.clear();
cin.ignore();
}
if(selectedDif != 1&&2&&3){ //If selected option isn't 1/2/3, this will run and will loop again. However I know this conflicts with the previous statement since this will run anyways.
cout << constants.xline() << "Wrong input, please try again." << endl;
}
else if(selectedDif == 1){
constants.setDiff(1);
constants.setStatPoints(15);
} else if(selectedDif == 2){
constants.setDiff(2);
constants.setStatPoints(10);
} else if (selectedDif == 3){
constants.setDiff(3);
constants.setStatPoints(5);}
}
}
The first function works perfectly you can type "aaa" or "a a a" and will work. However I'd like to know if there's a simpler way to do it. (Understandable for a beginner, just started 3 days ago lol; if it includes some advanced or less known code prefer to stay like this by now).
Now, the second one, I really have no idea how to fix it. I need something that if the user's input was an invalid character type, throw certain message, and if it's an int type, but out of the range, another message. And of course, run again if it fails. Did a lot of search and couldn't find anything that meet this requirements.
To check if the user input is an int, you could use the good() function.
int val;
cin >> val;
if( cin.good() ) {
// user input was a valid int
} else {
// otherwise
}
As for the range check, the syntax is a bit different.
This returns true if the number is not equal to 1 nor 2 nor 3:
selectedDif != 1 && selectedDif != 2 && selectedDif != 3
Another shorter way would be to use:
selectedDif < 1 || selectedDif > 3
Another thing, in c++, there are two keywords break and continue which will allow to reduce the code in the loops.

Why does this cause in infinite loop with chars but not doubles?

I feel like im doing something really silly wrong. I just want the program to tell the user when they are entering non-doubles, and continue to loop back to the cin where you enter a value.
I want the user to input any number. Then essential do this trivial math and repeat. Its working fine in that regard, the problem comes when some unexpected input like a char gets entered. Then the input somehow sends it into a loop where it loops the math problem, instead of just telling the user that they must type a number and looping back to cin type in a new number.
#include <iostream>
#include <cstdlib>
using std::cout; using std::cin; using std::endl;
long double domath(long double i)
{
cout << i << "/" << 2 << "=" << i/2 << endl;
cout << i/2 << "*" << 10 << "=" << (i/2)*10 << endl << endl;
cout << 5 << "*" << i << "=" << 5*i << "\n\n";
return 0;
}
int main()
{
long double in = 0;
while(true)
{
cin >> in;
if (cin.fail()) {
in = char(int(in));
}
domath(in);
}
system("pause>nul");
return 0;
}
You don't clear the cin in case of fail, and it infinitely tries to parse wrong input to double, failing every time. You need to clear the buffer in case of error:
if (cin.fail()) {
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
in = char(int(in));
}
Also, can't understand what you're trying to achieve with
in = char(int(in));
in is a long double variable and will hold the last value you assigned to it, no need to "convert" it to do math.
Couldn't you try doing something like this?
int x;
if(std::cin >> x)
doSomethingCool(x);
else
std::cout << "Error, not a valid integer!" << std::endl;
Exit your loop on bad input.
I think this just feels more natural/looks cleaner than clearing the buffer and all the other jazz. Just my opinion.
if (cin >> x) - Why can you use that condition?
edit: Bul's answer is still a good one though.

Else statement crashes when i enter a letter for a cin << int value

Alright, I have a question, I veered away from using strings for selection so now I use an integer. When the user enters a number then the game progresses. If they enter a wrong character it SHOULD give the else statement, however if I enter a letter or character the system goes into an endless loop effect then crashes. Is there a way to give the else statement even if the user defines the variable's type.
// action variable;
int c_action:
if (c_action == 1){
// enemy attack and user attack with added effect buffer.
///////////////////////////////////////////////////////
u_attack = userAttack(userAtk, weapons);
enemyHP = enemyHP - u_attack;
cout << " charging at the enemy you do " << u_attack << "damage" << endl;
e_attack = enemyAttack(enemyAtk);
userHP = userHP - e_attack;
cout << "however he lashes back causing you to have " << userHP << "health left " << endl << endl << endl << endl;
//end of ATTACK ACTION
}else{
cout << "invalid actions" << endl;
goto ACTIONS;
}
You haven't shown how you are reading the integer. But in general you want to do something like this:
int answer;
if (cin >> answer)
{
// the user input a valid integer, process it
}
else
{
// the user didn't enter a valid integer
// now you probably want to consume the rest of the input until newline and
// re-prompt the user
}
The problem is that your cin is grabbing the character and then failing, which leaves the character in the input buffer. You need to check whether the cin worked:
if( cin >> k) { ... }
or
cin >>k;
if(!cin.fail()) { ... }
and if it fails, clear the buffer and the fail bit:
cin.clear(); // clears the fail bit
cin.ignore(numeric_limits<streamsize>::max()); // ignore all the characters currently in the stream
EDIT: numeric_limits is found in the limits header file, which you include as per usual:
#include <limits>
Your problem is not with the else-statement, but with your input. If you do something like
cin >> i;
and enter a character, the streams error state is set and any subsequent try to read from the stream will fail unless you reset the error state first.
You should read a string instead and convert the strings contents to integer.