Checking for input "0" (zero) with cin - c++

I'm trying to have a program loop, accepting input and producing output until the user enters "0" as the input.
The problem is, my program accepts two values for input, like this:
cin >> amount >> currency;
So, I tried to have a while statement like this:
while (amount != 0 && currency != "") {
cin >> amount >> currency;
cout << "You entered " << amount << " " << currency << "\n";
}
However, the while statement always executes, even if I enter 0 as input.
How do I write the program such that it accepts two values as input except when the user enters 0, in which case it terminates?

You could use the fact that the right side of && is not executed if the left is false:
#include <iostream>
#include <string>
int main()
{
int amount;
std::string currency;
while (std::cin >> amount && amount != 0 && std::cin >> currency)
{
std::cout << "You entered " << amount << " " << currency << "\n";
}
}
test run: https://ideone.com/MFd48

The problem is that you do your check on the next iteration, after you've already printed the message. What you probably want is something like the following pseudo-code:
while successfully read amount and currency:
if amount and currency have values indicating that one should exit:
break out of the while loop
perform the action corresponding to amount and currency
I'll leave the actual code to you, since I suspect this is homework, however here are some hints:
You can use break to prematurely exit out of a loop.
Your while line should look like while (cin >> amount && cin >> currency)

What are the data types of 'currency' and 'amount'?
If 'amount' is of type 'char' then its integer value for '0' would be something else depending on the encoding ( 48 for ASCII ). Thus when you call 'cout << amount' you see '0' but when you evaluate 'amount != 0' it returns true instead of false.

Related

Infinite loop created when inputting "yy" into a char variable that should only take a single character such as 'y' or 'n', "nn" does not break code

The code in the cont function asks the user if they want to play my game again.
The code works when receiving proper character inputs such as 'y' or 'n' as well as their respective capital letter variants, and the else block works properly to loop the function if an invalid input such as 'a' or 'c' is entered.
However during a test run, an input of 'yy' breaks the code causing the program to infinitely loop, running not only this cont function but my game function as well.
choice is stored as a char variable. I am wondering why the code even continues to run upon inputting multi-character inputs such as 'yy' or 'yes'. What's interesting is 'nn', 'ny' and other variations of multi-character inputs that begin with 'n' causes no issues and properly results in the else if block running as intended. Which prints "Thanks for playing." then ends the program.
Can variables declared as char accept inputs greater than 1 character? Does it only take the first value? And if so why does 'yy' cause a loop rather than the program running as intended by accepting a value of 'y' or 'Y'? How can I change my program so that an input of 'yy' no longer causes issues, without specific lines targeting inputs such as 'yy' or 'yes'.
#include <iostream>
#include <string> // needed to use strings
#include <cstdlib> // needed to use random numbers
#include <ctime>
using namespace std;
// declaring functions
void cont();
void game();
void diceRoll();
// variable declaration
string playerName;
int balance; // stores player's balance
int bettingAmount; // amount being bet, input by player
int guess; // users input for guess
int dice; // stores the random number
char choice;
// main functions
int main()
{
srand(time(0)); // seeds the random number, generates random number
cout << "\n\t\t-=-=-= Dice Roll Game =-=-=-\n";
cout << "\n\nWhat's your name?\n";
getline(cin, playerName);
cout << "\nEnter your starting balance to play with : $";
cin >> balance;
game();
cont();
}
// function declaration
void cont()
{
cin >> choice;
if(choice == 'Y' || choice == 'y')
{
cout << "\n\n";
game();
}
else if (choice == 'N' || choice == 'n')
{
cout << "\n\nThanks for playing.";
}
else
{
cout << "\n\nInvalid input, please type 'y' or 'n'";
cont(); // calls itself (recursive function!!!)
}
}
void game()
{
do
{
cout << "\nYour current balance is $ " << balance << "\n";
cout << "Hey, " << playerName << ", enter amount to bet : $";
cin >> bettingAmount;
if(bettingAmount > balance)
cout << "\nBetting balance can't be more than current balance!\n" << "\nRe-enter bet\n";
} while(bettingAmount > balance);
// Get player's numbers
do
{
cout << "\nA dice will be rolled, guess the side facing up, any number between 1 and 6 : \n";
cin >> guess;
if(guess <= 0 || guess > 6 )
{
cout << "\nYour guess should be between 1 and 6\n" << "Re-enter guess:\n";
}
} while(guess <= 0 || guess > 6);
dice = rand() % 6+1;
diceRoll();
if (dice == guess)
{
cout << "\n\nYou guessed correctly! You won $" << (bettingAmount * 6);
balance = balance + (bettingAmount * 6);
}
else
{
cout << "\n\nYou guessed wrong. You lost $" << bettingAmount << "\n";
balance = balance - bettingAmount;
}
cout << "\n" << playerName << ", you now have a balance of $" << balance << "\n";
if (balance == 0)
{
cout << "You're out of money, game over";
}
cout << "\nDo you want to play again? type y or n : \n";
cont();
}
void diceRoll()
{
cout << "The winning number is " << dice << "\n";
}
Does it only take the first value?
Yes, the >> formatted extraction operator, when called for a single char value, will read the first non-whitespace character, and stop. Everything after it remains unread.
why does 'yy' cause a loop
Because the first "y" gets read, for the reasons explained above. The second "y" remains unread.
This is a very common mistake and a misconception about what >> does. It does not read an entire line of typed input. It only reads a single value after skipping any whitespace that precedes it.
Your program stops until an entire line of input gets typed, followed by Enter, but that's not what >> reads. It only reads what it's asked to read, and everything else that gets typed in remains unread.
So the program continues to execute, until it reaches this part:
cin >> bettingAmount;
At this point the next unread character in the input is y. The >> formatted extraction operator, for an int value like this bettingAmount, requires numerical input (following optional whitespace). But the next character is not numerical. It's the character y.
This results in the formatted >> extraction operator failing. Nothing gets read into bettingAmount. It remains completely unaltered by the >> operator. Because it is declared in global scope it was zero-initialized. So it remains 0.
In addition to the >> extraction operator failing, as part of it failing it sets the input stream to a failed state. When an input stream is in a failed state all subsequent input operation automatically fail without doing anything. And that's why your program ends up in an infinite loop.
Although there is a way to clear the input stream from its failed state this is a clumsy approach. The clean solution is to fix the code that reads input.
If your intent is to stop the program and enter something followed by Enter then that's what std::getline is for. The shown program uses it to read some of its initial input.
The path of least resistance is to simply use std::getline to read all input. Instead of using >> to read a single character use std::getline to read the next line of typed in input, into a std::string, then check the the string's first character and see what it is. Problem solved.
cin >> bettingAmount;
And you want to do the same thing here. Otherwise you'll just run into the same problem: mistyped input will result in a failed input operation, and a major headache.
Why do you need this headache? Just use std::getline to read text into a std::string, construct a std::istringstream from it, then use >> on the std::istringstream, and check its return value to determine whether it failed, or not. That's a simple way to check for invalid input, and if something other than numeric input was typed in here, you have complete freedom on how to handle bad typed in input.

C++ Line break entered as input automatically if you give a cin an unexpected input inside loop

I think I'm having issues with the buffer of the input stream. Whenever I input a very large number (10 or more characters) or a letter for the number1 or number 2 variable the console freaks out and seems to automatically fill every input with a line break while looping forever.
I tried using std::cin.clear(); to stop it from automatically inputting a line break but that didn't work.
#include <iostream>
int main() {
while (1) {
std::string operatorChoice;
long int number1, number2;
number1 = 0;
number2 = 0;
std::cout << "<add>, <subtract>, <divide>, <multiply>, or <exit> ";
std::cin >> operatorChoice;
if (operatorChoice == "exit") {
break;
}
std::cout << "Number 1: ";
std::cin >> number1;
std::cout << "Number 2: ";
std::cin >> number2;
if (operatorChoice == "add") {
std::cout << number1 << " + " << number2 << " = " << number1 + number2 << "\n";
std::cout << std::endl;
}
}
}
Input:
add
1
e
Output:
1 + 0 = 0
<add>, <subtract>, <divide>, <multiply>, or <exit> Number 1: Number 2: (this part just repeats forever)
I'm hoping there's a way to make the second iteration over the loop act identical to the first and not start inputting line breaks.
When the input given to std::cin cannot be converted to the type of the variable it will write, it enters an error state, which can be queried with cin.fail() (or synonyms such as !cin). If it returns true (meaning that the failbit of the stream is set), then it means that the conversion failed. While in this fail state, cin will refuse to read any data until the failbit is cleared.
In the lines where you read the numbers from the user, you should use a loop that checks the fail state of the stream, if it returns false, then continue normal execution, otherwise, call std::cin.clear() to clear the failbit so cincan continue reading as usual.
Keep in mind that the faulty input will still be in the stream (i.e. the 'e' you entered will still be there, so if that input is read again as a int, it will fail again), so call std::cin.ignore(<A big number like 256>,'\n') to skip over the bad/faulty input, while prompting the user for correct input (The number passed to ignore is the number of characters it should skip). The '\n' argument means all the characters in the stream are ignored until the next line, without it the user would have to enter the 256 characters.

While loop isn't working when user inputs letters instead of integers? [duplicate]

In C++, how do you handle wrong inputs? Like, if the program asks for an integer, when you type a character it should be able to do something and then loop to repeat the input but the loop goes infinite when you input a character when an integer is need and vice versa.
The reason the program goes into an infinite loop is because std::cin's bad input flag is set due to the input failing. The thing to do is to clear that flag and discard the bad input from the input buffer.
//executes loop if the input fails (e.g., no characters were read)
while (std::cout << "Enter a number" && !(std::cin >> num)) {
std::cin.clear(); //clear bad input flag
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard input
std::cout << "Invalid input; please re-enter.\n";
}
See the C++ FAQ for this, and other examples, including adding a minimum and/or maximum into the condition.
Another way would be to get the input as a string and convert it to an integer with std::stoi or some other method that allows checking the conversion.
The top voted answer covers the solution really well.
In addition to that answer, this may help visualize what's going on a little better:
int main()
int input = 1;//set to 1 for illustrative purposes
bool cinState = false;
string test = "\0";
while(input != -1){//enter -1 to exit
cout << "Please input (a) character(s): ";//input a character here as a test
cin >> input; //attempting to input a character to an int variable will cause cin to fail
cout << "input: " << input << endl;//input has changed from 1 to 0
cinState = cin;//cin is in bad state, returns false
cout << "cinState: " << cinState << endl;
cin.clear();//bad state flag cleared
cinState = cin;//cin now returns true and will input to a variable
cout << "cinState: " << cinState << endl;
cout << "Please enter character(s): ";
cin >> test;//remaining text in buffer is dumped here. cin will not pause if there is any text left in the buffer.
cout << "test: " << test << endl;
}
return 0;
}
Dumping the text in the buffer to a variable isn't particularly useful, however it helps visualize why cin.ignore() is necessary.
I noted the change to the input variable as well because if you're using an input variable in your condition for a while loop, or a switch statement it may go into deadlock, or it may fulfill a condition you weren't expecting, which can be more confusing to debug.
Test the input to see whether or not it is what your program expects. If it is not, alert the user that the input they provided is unacceptable.
You can check it through the ASCII value if the ascii value s between 65 t0 90 or 97 to 122 the it would be character.

C++ mystical infinite loop

I just started learning C++ after previously coding with Java. The code below takes input from the user and validates the input. The first piece asks for the number of voters, which must be a positive number. If I enter a negative number the program behaves as I expected. It prints out the error message and asks for the input again. However, if I enter any other character, such as any alphabet letter I get an infinite loop in the console, asking for input and printing the error message. What am I doing wrong?
my code:
#include <iostream>
using namespace std;
struct dataT {
int numOfVoters = -1;
float preSpread = -1;
float votingError = -1;
};
void getUserInfo() {
dataT data;
while (data.numOfVoters == -1) {
cout << "enter the number of voters" << endl;
cin >> data.numOfVoters;
if (data.numOfVoters <= 0) {
data.numOfVoters = -1;
cout << "Invalid entry, please enter a number larger than zero." << endl;
}
}
while (data.votingError == -1) {
cout << "enter the percentage spread between candidates" << endl;
cin >> data.votingError;
if (data.votingError <= 0 || data.votingError >= 1) {
data.votingError = -1;
cout << "Invalid entry. Enter a number between 0 to 1." << endl;
}
}
while (data.preSpread == -1) {
cout << "Enter the precentage spread between the two candidates." << endl;
cin >> data.preSpread;
if (data.preSpread <= 0 || data.preSpread >= 1) {
data.preSpread = -1;
cout << "Invalid input. Enter a number between 0 and 1." << endl;
}
}
}
int main() {
getUserInfo();
return 0;
}
Console:
enter the number of voters
f
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
...
...
...
If you write cin >> integervariable but in cin there are character that cannot represent an integer, the input fails, !cin becomes true, and the character remain there until you don't reset the input state from the error and consume the wrong characters.
a proper check can be
while(integervariable has not good value)
{
cout << "prompt the user: ";
cin >> integervariable;
if(!cin) //something wrong in the input format
{
cin.clear(); //clear the error flag
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard the rubbish
cout << "prompt error message \n";
}
}
Your if statements are always true, you want something more like:
if (data.votingError < 0 || data.votingError > 1) {
...
then data.votingError can take on a value different from -1 and exit your loop.
The std::cin object will check whether or not it is in a valid state every time it reads. If you enter a char where your program expects an int, then you'll "break" the input stream. All subsequent calls to std::cin will then be effectively skipped until you manually reset the input stream. When this happens, you'll never be able to set your values to anything other than -1, and your if statement always evaluates to true, causing an infinite loop.
As an aside, you can check for failure state by including && cin in all of your tests. Input objects implicitly evaluate to true if the stream is in a valid state and to false if the stream is in a failure state instead.

Use cin.clear() or cin,ignore() for ONLY previous line input?

Is there a way to use cin.clear() or cin,ignore() for ONLY the previous line of input without clearing ALL previous input? For example in my code I prompt the user for input for each month, well if the input is less than 0 I would like the program to clear that negative input so that it does not get total into my calculation. Problem is it clears ALL previous input which still screws up the calculation. Thanks for any ideas in advance.
// prompt user for input, keep a total sum of data entered
for(int i = 0; i < 12; i++)
{
cout << "Enter total rainfall for " << year[i] << endl;
cin >> month[i];
total += month[i];
while(month[i] < 0)
{
cout << "Ony enter positive numeric values!" << endl;
cin.clear();
cin >> month[i];
}
}
You seem to be mixing up two distinct issues. ios_base::clear()
doesn't remove any input; it resets the error status of the stream.
istream::ignore( n, ch ), on the other hand, reads forward until n
characters have been extracted or a character ch is seen'
myInput.ignore( INT_MAX, '\n' ) should ignore everything up to (and
including) the next '\n'.
but your code has one thing that is very strange:
cin << month[i];
You can't output to std::cin.
You probably want something like this:
unsigned int month[12];
for(size_t i = 0; i < 12; i++)
{
cout << "Enter total rainfall for month " << i+1 << endl;
while (!(cin >> month[i]))
{
cout << "Invalid input, try again." << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
// you probably want to repeat ignore() stuff here
// so in case user inputs something like 10x, the "x" that was left
// in the stream gets discarded
}
Note the array of unsigned integers. This way input like "-5" is automatically considered invalid so you don't need the less than 0 check. Clearing the entire stream shuouldn't worry you - if the input operation succeeds, the relevant part is already stored in your array.