C++ : check whether an input is a number - c++

I want the user to enter a key and I want to check whether the key is a number or not, throw a message if it is not and exit if it is 0.
I read an answer that suggested the below method here : isdigit() c++, probably simple question, but stuck
int key;
while (true){
cout << "Enter Key (Press 0 to Exit) : ";
if (cin>>key){
if (key == 0){ break; }
//Code goes here
}
else{cout<<"Key should be a digit "<<endl;}
}
but my code goes into an infinite loop as soon as I enter an alphabet and I am not able to figure out why.
Any help would be appreciated or if there is a better alternate method for the same then do suggest.

cin>>key
try to read an int from the console.
If you enter a non number character the next read from cin will set the cin stream into error state and nothing can be read from cin anymore until you clear the error flags of the stream.
cin.clear();
resets the error state.
You also have to ignore the entered chars which results in failure mode with
cin.ignore();
Example:
int main()
{
int i;
while (1)
{
std::cin >> i;
if ( std::cin.fail())
{
std::cout << "Something went wrong with cin" << std::endl;
std::cin.clear();
std::cin.ignore();
}
else
{
std::cout << "input works, read: " << i << std::endl;
}
}
}
If you try to read a single digit form console look also here:
Capture characters from standard input without waiting for enter to be pressed

my code goes into an infinite loop as soon as I enter an alphabet
That's because you declared key as an int, so when std::cin fails to read an integer number the stream is set into an error state and the break statement inside the if's is no longer reachable.
A possible alternative is to read a line from the input stream as a string and then try to convert it to a number.
Now, given OP's question:
I want the user to enter a key and I want to check whether the key is
a number or not, ...
It's not clear to me (my fault, probably) if key has to be considered a single or a multi digit number. In the following snippet I'll show the latter case. Please, note that it may include the former too.
#include <iostream>
#include <string>
int main()
{
std::string line;
while ( std::getline(std::cin, line) )
{
if ( line.empty() ) continue;
try
{
int key = stoi(line);
if ( !key ) break;
// code that uses the key...
}
catch ( const std::invalid_argument &e )
{
std::cout << "Key should be a digit!\n";
}
catch ( const std::out_of_range &e )
{
std::cout << "The value entered can't be represented by an int.\n";
}
}
return 0;
}

Related

Problem with C++ understanding chars within float input

#include <iomanip>
#include <math.h>
int main() {
float x, a, b;
char conditions[] = { 'Y', 'y' };
std::cout << "Enter a number: ";
std::cin >> x;
if (!std::cin) {
std::cout << "error";
}
else {
a = x * x;
std::cout << "A is: " << a << std::endl;
}
}
//I need to create an if statement or a loop to
//ask to input float x again if char conditions were input instead.
I have a problem I've been trying to find an answer to for weeks. From the code you can see that !std::cin condition won't accept any chars, therefore an error will be printed. I however need an exception where if 'y' || 'Y' is inputted it loops back to the std::cin >> x; and asks for a float value again until it is provided, however if any other char is inputted like 'h' it would obviously go back to the error message.
I've tried multiple if statements, checked recursives but no luck. The problem is that I can't make the exceptions because if 'y' is inputted then the program doesn't understand it because the std::cin >> is asking for a number not a char...
The task description is unclear. On the one hand, you state that you want the program to ask for a float value again, until one is provided. On the other hand, you state that this should only happen when the user enters "y" or "Y", but when the user enters anything else, it should print an error message instead. This is contradictory.
If you want your program to check whether the user enters a certain character, then you must read the input as a string, instead of as a number. I recommend that you use std::getline for this.
Once you have determined that the user did not enter "Y" or "y", you can use the function std::stof to convert the string to a number.
When the user doesn't enter a number, I don't understand why you say you want to loop back to the input on "y" and "Y", but want to print an error message instead on all other inputs. However, if that is what you want, then this is how you can implement it:
#include <iostream>
#include <string>
int main()
{
std::string input;
float x;
for (;;) //infinite loop, equivalent to while(1)
{
//prompt user for input
std::cout << "Enter a number: ";
//read one line of input
std::getline( std::cin, input );
if ( !std::cin )
throw std::runtime_error( "unexpected stream error!" );
//check if "y" or "Y" was entered
if ( input == "y" || input == "Y" )
continue;
//attempt to convert input to a number
try
{
x = std::stof( input );
}
catch ( std::invalid_argument )
{
printf( "Unable to convert to number\n" );
break;
}
catch ( std::out_of_range )
{
printf( "Number is out of range\n" );
break;
}
std::cout << "You entered the following number: " << x << "\n";
}
}
This program works as intended (based on your contradictory description). If you enter "y" or "Y", it will loop back to the prompt for user input:
Enter a number: y
Enter a number: y
Enter a number: y
Enter a number: 67.5
You entered the following number: 67.5
If you instead provide a non-number input that is not "y" or "Y", it will print an error message, instead of looping back to the input:
Enter a number: y
Enter a number: y
Enter a number: j
unable to convert to number
This behavior does not make sense, but it appears to be what you are asking for.
This program does have one small problem, though. It will accept 6sdfjloj as valid input for the number 6:
Enter a number: 6sdfjloj
You entered the following number: 6
It would probably be more meaningful to reject such input with an error message.
Doing this is also possible, by passing a second argument to std::stof, in order to determine how many characters were converted. If not all characters were converted, you can reject the input. On the other hand, you may want to accept trailing whitespace characters (as determined by std::isspace), but reject the input if there are any other trailing characters. This would make sense: Because std::stof accepts leading whitespace characters, it makes sense to also accept trailing whitespace characters.
In my opinion, it would be more meaningful to demonstrate these programming possibilities with the following task:
The user should instead be prompted with the following message:
"Please enter a number, or enter "q" to quit: "
If the user enters "q" or "Q", the program should exit.
Otherwise, it should determine whether the user entered a valid number. If the input is a valid number, the program should say so and print the number, otherwise it should print an error message. Either way, the program should loop back to the initial prompt.
The solution to this problem would be the following:
#include <iostream>
#include <string>
#include <cctype>
int main()
{
std::string input;
float x;
std::size_t pos;
for (;;) //infinite loop, equivalent to while(1)
{
//prompt user for input
std::cout << "Please enter a number, or enter \"q\" to quit: ";
//read one line of input
std::getline( std::cin, input );
if ( !std::cin )
throw std::runtime_error( "unexpected stream error!" );
//check if "q" or "Q" was entered
if ( input == "q" || input == "Q" )
{
std::cout << "Quitting program!\n";
break;
}
//attempt to convert input to a number
try
{
x = std::stof( input, &pos );
}
catch ( std::invalid_argument )
{
printf( "Unable to convert to number!\n" );
continue;
}
catch ( std::out_of_range )
{
printf( "Number is out of range!\n" );
continue;
}
//make sure that any trailing characters are whitespace,
//otherwise reject input
for ( std::size_t i = pos; input[i] != '\0'; i++ )
{
if ( !std::isspace( static_cast<unsigned char>(input[i]) ) )
{
std::cout << "Unexpected character encountered!\n";
//we cannot use continue here, because that would jump
//to the next iteration of the innermost loop, but we
//want to jump to the next iteration of the outer loop
goto continue_outer_loop;
}
}
std::cout << "Input is valid, you entered the following number: " << x << "\n";
continue_outer_loop:
continue;
}
}
This program has the following output:
Please enter a number, or enter "q" to quit: 67.5
Input is valid, you entered the following number: 67.5
Please enter a number, or enter "q" to quit: 32.1
Input is valid, you entered the following number: 32.1
Please enter a number, or enter "q" to quit: sdfjloj
Unable to convert to number!
Please enter a number, or enter "q" to quit: 6sdfjloj
Unexpected character encountered!
Please enter a number, or enter "q" to quit: q
Quitting program!
As you can see, it now also properly rejects input such as 6sdfjloj.
Note that this program contains one goto statement. It was appropriate to use it, in order to jump out of a nested loop. This is considered an acceptable use of goto. However, you should not use goto except in rare situations, in which there is no cleaner alternative. So please don't get used to using it.
Seems like you want to take a floating number as input.
If the user gives any invalid input like a character, you want to show an error message and take input again.
If this is the case, taking input using string might be a better way.
Take the input as a string, check if the string contains any additional character other than digits and a dot.
If it does, take input again. So you can use a loop to do that.
If you get a valid string, then calculate the result and stop taking input.
Sample code:
int main()
{
float x, a, b;
char conditions[] = { 'Y', 'y' };
string input;
while(true)
{
std::cout << "Enter a number: ";
std::cin >> str;
if (input_contains_any_other_character)
{
std::cout << "error";
// going back to the beginning of the while loop
}
else
{
// first convert the string and keep it in the variable x
// then calculate your result
a = x * x;
std::cout << "A is: " << a << std::endl;
break; // stop taking further input
}
}
}

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

Need some help finding a logical error in my while loop

I am learning C++, and I am doing some exercises in the book I am using. One of them asks to write a program that asks a user how many numbers they want to add up. Then prompt for the numbers the user wants to add or to enter '|' once finished. The numbers are then pushed into a vector. Part of the program asks to check if the size of the vector is equal to the original number of input items and that is where I keep getting an error.
cout << "Please enter the numbers and | once you are done: ";
while(true)
{
for(int num; cin >> num; )
{
if(num == '|')
{
break;
}
ints.push_back(num);
}
if(ints.size() != n)
{
cout << "There are more or less numbers in the vector than originally specified\n"
<< "Vector will be cleared; please re-enter the values: ";
ints.clear();
continue;
}
else
{
break;
}
}
The problem is that if the number of input is off, the message goes into an infinite loop and I am not sure how to fix it.
EDIT: n is the variable that holds in the number of values user wanted to enter.
Thanks!
num is an integer and cin >> num won't extract | symbol. Comparison num == '|' may not work as expected because num could have the numeric value of | ascii symbol even when user did not input any | symbol. You should properly handle end marker reading:
// loop will break when user enters `|` because it is not an integer
// setting failbit of cin
for(int num; cin >> num;)
{
ints.push_back(num);
}
cin.clear(); // reset failbit making cin able to read again
// check the end marker entered by user
{
string end_marker;
cin >> end_marker;
if("|" != end_marker)
{
// use of endl will flush the stream ensuring that
// printed text won't stuck in the buffer
cout << "Please use | as end marker" << endl;
continue;
}
}
Here is how I implemented it. I am worried about the logic in your while loop. I had been taught to avoid while(true) whenever possible. You know the logic behind how your code should work. With more practice you'll start to recognize the conditions you need to use. I am sure there are better ways to do it. But this is the way I tried it.
But to answer your question, the main reason it is failing is because integers cannot compare themselves with characters.
if(num == '|')
That does not work since num is an integer and not a character.
Normally I would implement this in a class and since global variables are not highly looked upon I created my own namespace. You'll have to finish the rest of the logic yourself however:
#include <iostream>
#include <vector>
#include <string>
namespace global
{
std::vector<std::string> strings;
std::vector<int> ints;
std::string a = " ";
int num = 0;
}
void doWork()
{
std::cout << "Please enter the number of integers you would like to add up: ";
std::cin >> global::num;
std::cout << "Please enter the numbers and | once you are done: ";
while (global::a != "|")
{
std::cin >> global::a;
global::strings.push_back(global::a);
}
global::strings.pop_back();
for(auto &e : global::strings)
{
global::ints.push_back(std::stoi(e));
}
}
int main()
{
doWork();
if(global::ints.size() != global::num)
{
std::cout << "Size of vector does not match the size specified. Clearing vector" << std::endl;
global::ints.clear();
global::strings.clear();
global::num = 0;
global::a = " ";
doWork();
}
}
I made a vector of char's and converted those into integers so that way you could add them up. The while loop should be checking for | rather than always running true. It then will check the size of the vector in the end, clear it if it does not match, and ask you to do it again. This is the best way that I could think of doing it.
EDIT: as VTT pointed out, char can only do one character at a time. I have converted it into a string in order to handle the conversion.
EDIT 2: reset the values of global::num and global::a to their default at the end of the failure in order to prevent crashing.

How do I sanitise cin?

Say I have a program that takes in integers. How do I stop the program from falling apart if the user enters an out of range number, or a letter or something?
The cin's base class is std::basic_istream. The input stream indicates a recoverable error in case it cannot extract the requested data from the stream. In order to check for that error bit, std::basic_istream::fail() method must be used — it returns true if there was a failure or false if everything is alright. It is important to remember that if there is an error, the data is left in the stream and, of course, the error bit(s) must also be cleared using std::basic_istream::clear(). Also, a programmer must ignore incorrect data, or otherwise an attempt to read something else will fail again. For that purpose, std::basic_istream::ignore() method can be used. As for the valid range of values, it must be checked manually. Okay, enough theory, here is a simple example:
#include <limits>
#include <iostream>
int main()
{
int n = 0;
for (;;) {
std::cout << "Please enter a number from 1 to 10: " << std::flush;
std::cin >> n;
if (std::cin.fail()) {
std::cerr << "Sorry, I cannot read that. Please try again." << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
if (n < 1 || n > 10) {
std::cerr << "Sorry, the number is out of range." << std::endl;
continue;
}
std::cout << "You have entered " << n << ". Thank you!" << std::endl;
break;
}
}
Hope it helps. Good Luck!
I prefer reading the input as strings, and then sanitizing them with boost::lexical_cast<>:
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
int main () {
std::string s;
while( std::cin >> s) {
try {
int i = boost::lexical_cast<int>(s);
std::cout << "You entered: " << i << "\n";
} catch(const std::bad_cast&) {
std::cout << "Ignoring non-number: " << s << "\n";
}
}
}
Postscript: If you are allergic to Boost, you can use this implementation of lexical_cast:
template <class T, class U>
T lexical_cast(const U& u) {
T t;
std::stringstream s;
s << u;
s >> t;
if( !s )
throw std::bad_cast();
if( s.get() != std::stringstream::traits_type::eof() )
throw std::bad_cast();
return t;
}
something like this should do you need to clear the buffer after checking aswell if i remember right
if (cin.fail())
{
cout<<"need to put a number"<<endl;
cin.clear();
cin.ignore();
}
If You dont want to add libraries to your code you could also use do..while() statements.
in your do while you will ask for user input and then receive it to your variable then in the while part you will be able to check that this is the data you are expecting if not continue to ask for the data.
just another option ....even though the answer already mentioned should work more than adequately
You can use the following code for simplest and fast checking of valid input in int :
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
int intb;
while( !( cin>>intb ) ){
cin.clear ();
cin.ignore (1000, '\n');
cout<<"Invalid input enter again: "<<endl;
}
cout<<"The value of integer entered is "<<b<<endl;
return 0;
}
The while loop keeps on iterating until it gets the right input.
cin.clear() changes the error control state.
cin.ignore() removes clear the input stream so that new input can be taken again. If not done thw while loop will be in infinite state.

While loop with try catch fails at bad cin input

I can't seem to figure out why this falls into a loop after getting non-int input. I've tried cin.flush(), which doesn't seem to exist, cin.clear(), which seems like it should work, even cin.sync() after reading someone else post about it working, but didn't seem to make much sense. Also tried cin.bad().
Thank you very much for any help
Please enter the first number: f
Sorry, I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?Sorry,
you d on't get any more tries. Press
any key to continue . . .
#include <iostream>
using namespace std;
int main(){
int entry;
int attempts = 1;
int result;
while(attempts <= 5) {
try {
cout << "\n\nPlease enter the first number: ";
cin >> entry;
if (cin.fail())
throw "Sorry, I don't think that's a number?";
if (entry < 0)
throw "Sorry, no negative numbers. Try something else? ";
cout << "\nNow the second number: ";
cin >> entry;
cin.clear();
cin.get();
}
catch (char* error) {
cout << error;
attempts++;
}
}
if (attempts > 5)
cout << "Sorry, you don\'t get any more tries.\n";
system("pause");
return 0;
}
You should think carefully what you want to do if user gives invalid input in this case. Usually in these cases the best solution is to read one line from the input and throw it away.
Try putting cin.clear() and std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n'); in your catch clause. cin.clear() clears the failure state in cin, and cin.ignore() throws away rest of the line waiting in the input buffer.
(And yes, you probably should rethink your use of exceptions).
The most straight-forward (but not usually the easiest nor the fastest) way of dealing with validation of line-based input is to always read it line at a time. This way no extra whitespace (such as linefeed characters) is left unread in the buffer in any case, and discarding erroneous input is also quite automatic.
// Infinite loop for retrying until successful
while (true) {
// Ask the user something
std::cout << prompt;
// Read the answer (one full line)
std::string line;
if (!std::getline(std::cin, line))
throw std::runtime_error("End of input while expecting a value");
// Put the line read into iss for further parsing
std::istringstream iss(line);
int val;
// Read val from iss and verify that reading was successful and
// that all input was consumed
if (iss >> val && iss.get() == EOF) return val;
std::cout << "Invalid input, try again!\n";
}
It is fun to make a BASIC style input function out of this:
template <typename Val> void input(std::string const& prompt, Val& val) {
// (the above code goes here, slightly adjusted)
}
int main() {
int w;
double l;
input("Enter weight in kg: ", w);
input("Enter length in m: ", l);
std::cout << "BMI: " << w / (l * l) << std::endl;
}
Notes for the pedantics who were going to downvote me:
function input should be specialized for std::string
exceptions thrown by the input function should be caught in main
My Problem was to block char input to a cin >> number
This error caused an 'infinite' loop showing my prompt cout << prompt
with no way of exit but kill the process ...
The following shows what worked for me!
========================================
double fi_trap_d() // function to return a valid range double catching errors
{
double fi_game_sec;
//-------------------------------------------
do
{
fi_game_sec = -1;
cout << fi_game_sec_c;
//------------------------------
cin.ignore(); // (1)
//------------------------------
try
{ cin >> fi_game_sec; cin.clear(); } // (2)
catch (...) //out_of_range)
{
fi_game_sec = -1;
cout << " Dis am an error!\n";
// just loop back as we asked for a number
}
} while (fi_game_sec < 1);
//-------------------------------------------
return fi_game_sec;
}
========================================
Despite trying the " Dis am an error! " has NEVER shown up.
The key was (1) & (2) !
Exceptions should be used to handle exceptional, unexpected situations. Incorrect input from a user is neither unexpected nor exceptional -- it's more or less the norm. Personally, I tend to just ignore most bad input completely (when it can't be prevented). When (and only when) they enter something unusable repeatedly is it even worth pointing it out to them. As such, I'd tend to write the code something like:
char ch;
int attempts = 0;
std::cout << "Please enter the first number: ";
do {
cin >> ch;
attempts++;
if (attempts > 5)
std::cerr << "The only allowable inputs are '0' through '9'\n";
} while (cin.good() && !isdigit(ch));
int first_number = ch - '0';
This reads the input as a character, so it's always removed from the input stream. Then it attempts to validate the input, and if it fails, attempts to read again. Of course, you might want/need to get a little more elaborate, such as reading an entire line, attempting to convert it to a number, and reading another line if that fails.
Why are you doing this with exceptions? You're not going to kill the program on input, so you shouldn't throw an exception.
Just print out your error message and attempt to read in again.
It looks like you would be better off with iostream's native exceptions. Enable with
cin.exceptions( ios::failbit );
try {
…
} catch( ios_base::failure & ) {
cin.clear();
…
}
Never, ever throw an an object not derived from std::exception, and especially not a native type like char*.