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

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.

Related

loop involving "cin.fail()" running multiple times

I am having trouble with the following code. It is meant to keep asking for a valid input until an integer or double is inputted. It works as intended for characters, however when I input a string of length more than 1, it will run the loop multiple times. For example, the input "hello" with cause "Please enter a valid number" to be printed 5 times. Interestingly "h llo" will only print the sentence 4 times.
int gamenumber;
while(true)
{
cin >> gamenumber;
if(cin.fail())
{
cout << "Please enter a valid number" << endl;
cin.clear();
cin.ignore();
} else
break;
I did manage to fix this issue by replacing "cin.ignore()" with "cin.ignore(1000, '\n')".
But regardless, it's bugging me that I don't understand why "cin.ignore()" alone doesn't fix this? Is there a way to fix the above code without using "cin.ignore(1000, '\n')"? (This is part of a homework assignment, and we may not be allowed to use "cin.ignore(1000, '\n')")
Thank you!
You need use ignore with the overloaded one, see this anser here.
Or you can just need to run getline to drain the contents, but this way is slower and unnecessary.
#include <iostream>
#include <string>
int main()
{
double n;
while( std::cout << "Please, enter a number\n"
&& ! (std::cin >> n) )
{
std::cin.clear();
std::string line;
std::getline(std::cin, line);
std::cout << "I am sorry, but '" << line << "' is not a number\n";
}
std::cout << "Thank you for entering the number " << n << '\n';
}

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 ;)

Looping if user input invalid

I want to create a program that when a user inputs something that I didn't define, the program prompts him again.
I did it with if statements but it only loops for 1 time and doesn't do it again. I tried loops but whenever the input is false it just breaks the condition and refuses all inputs alike. In c++.
Any help is much appreciated.
#include <iostream>
#include <string>
using namespace std;
void xD(){string x;
do{cout << "Retry\n";
cin >> x;}while(true);}
//declaring a function to make the shop
void shop(){
string x;
float coins = 500;
float bow_cost = 200;
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
cin >> x;
// if u chose bow you get this and get to choose again
if (x == "bow"){
cout << "you bought the bow.\n you now have " <<coins - bow_cost << " coins." << endl; cin >> x;}
/*now the problem that whenever I excute the code and type something other than bow it gives me the cin only once more and then fails even if I type bow in the 2nd attempt*/
//in my desperate 5k attempt, I tried creating a function for it.. no use.
//i want it o keep prompting me for input till i type "bow" and the other block excutes. but it never happens.
else{xD();}
}
int main(){
string name;
string i;
cout << "if you wish to visit the shop type \"shop\"\n";
cin >> i;
if(i == "shop"){shop();}
else{cin >> i;}
return 0;
}
The problem lies on the condition in this loop block
void xD(){
string x;
do{
cout << "Retry\n";
cin >> x;
}while(true);
}
The while(true) condition makes it loops forever regardless of the input. To fix this, you can change the condition:
void xD(){
string x;
do{
cout << "Retry\n";
cin >> x;
}while(x!="bow");
cout << "you bought the bow. and some other messages"<<endl;
}
That should work. However, it is still too complicated for me. This can be simplified into the snippet below:
void shop(){
string x;
float coins = 500;
float bow_cost = 200;
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
cin >> x;
while (x!="bow"){
cout << "Retry\n";
cin>>x;
}
cout << "you bought the bow.\n you now have " <<coins - bow_cost << " coins." << endl; cin >> x;
}
Instead of doing this approach (which is checking the condition only once):
if (x == "bow"){
cout << "you bought the bow.\n you now have " <<coins - bow_cost << "
coins." << endl; cin >> x;
} else{
xD();
}
which is actually a RECURSIVE invocation to the method xD()
you should do a do-while loop,
example:
while (x.compare("bow") != 0)
{
cout << "sorry, wrong input, try again...";
cin >> x;
}
note the use of the compare method instead of the == operator
here more about it in the documentation
You can use return value of cin >> [your input object] here to check status or istream's method fail(). As soon as input stream fails to parse whole or part of streams it fails and stay in state of failure until you clear it. Unparsed input is preserved (so you can try to parse it differently?)m so if you try to >> again to object of same type, you'll get same failure. To ignore N chars of imput, there is method
istream::ignore(streamsize amount, int delim = EOF)
Example:
int getInt()
{
while (1) // Loop until user enters a valid input
{
std::cout << "Enter an int value: ";
long long x; // if we'll use char, cin would assume it is character
// other integral types are fine
std::cin >> x;
// if (! (std::cin >> x))
if (std::cin.fail()) // has a previous extraction failed?
{
// yep, so let's handle the failure, or next >> will try parse same input
std::cout << "Invalid input from user.\n";
std::cin.clear(); // put us back in 'normal' operation mode
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); // and remove the bad input
}
// Thechnically you may do only the above part, but then you can't distingusih invalid format from out of range
else if(( x > std::numeric_limits<int>::max()) ||
( x < std::numeric_limits<int>::min()))
{
std::cout << "Invalid value.\n";
}
else // nope, so return our good x
return x;
}
}
For strings parsing is almost always successful but you'll need some mechanism of comparison of string you have and one that is allowed. Try look for use of std::find() and some container that would contain allowed options, e.g. in form of pair<int,string>, and use int index in switch() statement (or use find_if and switch() within the function you give to it).
Consider that if() statement is a one_direction road, it checks the condition and if the condition was satisfied it goes to its bracket and do blah blah blah , if there is any problem with condition compiler passes ifand jump to compile other codes.
Every time that you begin to compile the codes it begins from int main() function. You did the wrong thing in the if and else statements again
Here is the correct code .I did the necessary changes.
#include "stdafx.h"
#include <iostream>
#include <string>
using std::string;
using std::cin;
using std::cout;
#define coins 500 ;
#define bow_cost 200 ;
int shop(string x)
{
//There is no need to allocate extra memory for 500 and 200 while they are constant.``
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
do
{
cout << "Input another :\n";
cin >> x;
if (x == "bow")
{
return (coins - bow_cost); //return to function as integer
}
} while (true);
}
int main()
{
string name, i;
cout << "if you wish to visit the shop type \"shop\"\n";
cin >> i;
if (i == "shop")
{
cout << "Input :\n";
cin >> name;
cout << shop(name) << "you bought the bow.\n you now have " << " coins." << "\n";
}
//argument passed to shop funnction parameters.
system("pause");
return 0;
}

How to make cin >> not convert float to integer?

I have the following simple code:
#include <iostream>
int main()
{
int a;
std::cout << "enter integer a" << std::endl;
std::cin >> a ;
if (std::cin.fail())
{
std::cin.clear();
std::cout << "input is not integer, re-enter please" <<std::endl;
std::cin >>a;
std::cout << "a inside if is: " << a <<std::endl;
}
std::cout << "a is " << a <<std::endl;
std::cin.get();
return 0;
}
When I run the above code and input: 1.5, it outputs: a is 1. FYI: I compile and run the code with gcc 4.5.3.
This means that if cin expects an integer but sees a float, it will do the conversion implicitly. So does this mean that when cin sees a float number, it is not in fail() state? Why this is the case? Is it because C++ does implicit conversion on >> operator?
I also tried the following code to decide whether a given input number is integer following idea from this post: testing if given number is integer:
#include <iostream>
bool integer(float k)
{
if( k == (int) k) return true;
return false;
}
int main()
{
int a;
std::cout << "enter integer a"<< std::endl;
std::cin >> a ;
if (!integer(a))
{
std::cout << "input is not integer, re-enter please" ;
std::cin.clear();
std::cin >> a;
std::cout << "a inside if is: " << a <<std::endl;
}
std::cout << "a is " << a <<std::endl;
std::cin.get();
return 0;
}
This block of code was also not able to test whether a is integer since it simply skip the if block when I run it with float input.
So why this is the case when getting user input with cin? What if sometimes I want the input to be 189, but typed 18.9 by accident, it will result in 18 in this case, which is bad. So does this mean using cin to get user input integers is not a good idea?
thank you.
When you read an integer and you give it an input of 1.5, what it sees is the integer 1, and it stops at the period since that isn't part of the integer. The ".5" is still in the input. This is the reason that you only get the integer part and it is also the reason why it doesn't seem to wait for input the second time.
To get around this, you could read a float instead of an integer so it reads the whole value, or you could check to see if there is anything else remaining on the line after reading the integer.
When reading user input I prefer not to use operator>> as user input is usally line based and prone to errors. I find it best to read a line at a time and validate:
std::string line;
std::getline(std::cin, line);
This also makes it easy to check for different types of numbers.
std::stirngstream linestream(line);
int val;
char c;
if ((linestream >> val) && !(linestream >> c))
{
// Get in here if an integer was read.
// And there is no following (non white space) characters.
// i.e. If the user only types in an integer.
//
// If the user typed any other character after the integer (like .5)
// then this will fail.
}
Of course boost already supports this:
val = boost::lexical_cast<int>(linestream); // Will throw if linestream does
// not contain an integer or
// contains anything in addition
// to the integer.
Boost of course will convert floats as well.
I have some snippet which is kind a poor coding, but it works.
This method is pretty simple, but doesn't handle case when input value is invalid.
See more: https://en.cppreference.com/w/cpp/string/byte/atof
static float InputFloat(std::string label)
{
std::string input;
std::cout << label;
std::cin >> input;
return atof(input.c_str());
}
int main()
{
float value = InputFloat("Enter some float value: ");
std::cout << "value = " << value;
return 0;
}

Why does this cin loop never end?

In the following code, if the user inputs something that is not an int, the program goes into an infinite loop. Why does this happen, and what should I do to fix it?
#include <iostream>
#include <string>
using namespace std;
int main()
{
int i;
char str[100];
while (!(cin >> i))
{
gets(str);
cout << "failure read!" << endl;
}
cout << "successful read!" << endl;
return 0;
}
Clear the error state:
int main()
{
int i;
char str[100];
while (!(cin >> i))
{
cin.clear();
cin.getline(str,100);
cout << "failure read!" << endl;
}
cout << "successful read!" << endl;
return 0;
}
I think that you want to replace the while loop with an if statement, with this loop, you'll continuously read from cin while an error occurs. However, cin is structured so that after an error occurs, you must manually clear the error state, and since you're not doing that here this will go into an infinite loop. Using an if statement tries to read a value and then let's you know whether or not it succeeded.
Additionally, this really isn't a good way to read from cin. It's brittle and any invalid input can totally take down your program, since gets is inherently unsafe. For a discussion of a safer and more robust way to get input in C++, check out http://www.stanford.edu/class/cs106l/course-reader/Ch3_Streams.pdf