C++ Exception handling Inside loop not working [duplicate] - c++

I am just trying to write a simple program that reads from cin, then validates that the input is an integer. If it does, I will break out of my while loop. If not, I will ask the user for input again.
My program compiles and runs just fine, which is great. But it doesn't prompt for new input if I enter a non numeric value. What gives?
#include <iostream>
using namespace std;
int main() {
bool flag = true;
int input;
while(flag){
try{
cout << "Please enter an integral value \n";
cin >> input;
if (!( input % 1 ) || input == 0){ break; }
}
catch (exception& e)
{ cout << "Please enter an integral value";
flag = true;}
}
cout << input;
return 0;
}

C++ iostreams don't use exceptions unless you tell them to, with cin.exceptions( /* conditions for exception */ ).
But your code flow is more natural without the exception. Just do if (!(cin >> input)), etc.
Also remember to clear the failure bit before trying again.
The whole thing can be:
int main()
{
int input;
do {
cout << "Please enter an integral value \n";
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} while(!(cin >> input));
cout << input;
return 0;
}

Don't use using namespace std; Instead import what you need.
It's better to do input a line at a time. This makes behavior much more intuitive if you have multiple words on one line, or if you press enter before typing anything.
#include <iostream>
#include <sstream>
#include <string>
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::flush;
using std::getline;
using std::istringstream;
using std::string;
int main() {
int input;
while (true)
{
cout << "Please enter an integral value: " << flush;
string line;
if (!getline(cin, line)) {
cerr << "input failed" << endl;
return 1;
}
istringstream line_stream(line);
char extra;
if (line_stream >> input && !(line_stream >> extra))
break;
}
cout << input << endl;
return 0;
}

Related

Modern Way of checking if C++ input is integer or not

I want to add the check-in my c++ code that user can not enter not integral values in reg. If he inputs, he is prompted again. I saw the solutions in the stack overflow that was of 2011 (How to check if input is numeric in C++). Is there some modern or good way now or is it same?
I tried using ifdigit() in ctype.h
// Example program
#include <iostream>
#include <ctype.h>
using namespace std;
int main()
{
int x;
cout<<"Type X";
cin>>x;
if(!isdigit(x))
{
cout<<"Type Again";
cin>>x;
}
}
but it didnt worked
here is my actual problem where I want to add check.
cout << "Type Reg # of Student # " << i + 1 << endl;
do
{
cin >> arr[i][j];
} while (arr[i][j] < 999 || arr[i][j] > 9999);
where i and j are in dec. in for loop. I just want to add check that input is not string or something like this. Cant rely on 2011 answer
Check out the below example.
All the magic happens inside to_num(), which will handle white space before and after the number.
#include <iostream>
#include <sstream>
#include <string>
#include <tuple>
auto to_num(const std::string& s)
{
std::istringstream is(s);
int n;
bool good = (is >> std::ws >> n) && (is >> std::ws).eof();
return std::make_tuple(n, good);
};
int main()
{
int n;
bool good;
std::cout << "Enter value: ";
for(;;)
{
std::string s;
std::getline(std::cin, s);
std::tie(n, good) = to_num(s);
if(good) break;
std::cout << s << " is not an integral number" << std::endl;
std::cout << "Try again: ";
}
std::cout << "You've entered: " << n << std::endl;
return 0;
}
Explanation of what's going on inside to_num():
(is >> std::ws >> n) extracts (optional) leading white space and an integer from is. In the boolean context is's operator bool() will kick in and return true if the extraction was successful.
(is >> std::ws).eof() extracts (optional) trailing white space and will return true if there is no garbage at the end.
UPDATE
Here is a slightly cleaner version that uses Structured binding declaration and Class template argument deduction available in c++17:
#include <iostream>
#include <sstream>
#include <string>
#include <tuple>
auto to_num(const std::string& s)
{
std::istringstream is(s);
int n;
bool good = (is >> std::ws >> n) && (is >> std::ws).eof();
return std::tuple(n, good); // look ma, no make_tuple
};
int main()
{
std::cout << "Enter value: ";
for(;;)
{
std::string s;
std::getline(std::cin, s);
auto [n, good] = to_num(s); // structured binding
if(good)
{
std::cout << "You've entered: " << n << std::endl;
break;
}
else
{
std::cout << s << " is not an integral number" << std::endl;
std::cout << "Try again: ";
}
}
return 0;
}
If you properly handle errors, you'll end up with a prompt / input loop that looks something like this:
#include <iostream>
#include <limits>
int getInput() {
while (true) {
std::cout << "Please enter a number between 80 and 85: ";
int number = 0;
std::cin >> number;
std::cout << "\n";
if (std::cin.eof()) {
std::cout << "Unexpected end of file.\n";
std::cin.clear();
continue;
}
if (std::cin.bad() || std::cin.fail()) {
std::cout << "Invalid input (error reading number).\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
if (number < 80 || number > 85) {
std::cout << "Invalid input (number out of range).\n";
continue;
}
return number;
}
// unreachable
return 0;
}
int main() {
int number = getInput();
std::cout << number << std::endl;
}
We can omit the range check if we don't need it.
We handle std::cin.eof() (e.g. user presses ctrl+Z on Windows) separately from the other conditions, since for eof there's nothing to ignore.
This follows the standard C++ stream behavior for whitespace and number conversion (i.e. it will accept inputs with extra whitespace, or inputs that only start with numeric values).
If we want more control over what we want to accept, or don't want conversion to depend on the locale, we have to use std::getline to read input from std::cin, and then do the string conversion ourselves (either with std::stringstream as in Innocent Bystander's answer, or using std::strtol, or std::from_chars).

Trying to make a loop to check the string for numbers only and negative numbers allowed in C++ im new to programming this is a class project

I'm trying to make a loop to check input strings for numbers only, and negative numbers are allowed. I'm new to programming, this is for a class project.
This code works, to an extent. When it shows the output, it does not show the first number, and does not allow - to be used. I cannot figure out where I'm going wrong in this.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
string userInput;
int i = 0;
bool checkInput(int);
int main()
{
do
{
cout << "Please enter a numeric value : ";
string userInput;
cin >> userInput[i];
}
while (!checkInput(userInput[i]));
system("pause");
return 0;
}
bool checkInput(int input)
{
string userInput;
int i;
cin >> userInput;
for (int i = 0; i < userInput.length(); i++)
if (isdigit(userInput[i]))
{
cout << "\nYour input " << userInput << " is a valid numeric input." << endl;
return true;
}
else
{
cout << "Please enter a valid numeric value: ";
cin >> userInput[i];
return false;
}
}
Your code doesn't work because you are not utilizing std::string correctly.
When main() prompts the user, it reads into a char of an empty std::string, which is undefined behavior. You should be reading into the std::string itself without calling its operator[] at all. operator>> has an overload for reading std::string values.
checkInput() is just all kinds of wrong. It takes an int as input instead of a std::string, but ignores that input and waits for the user to type in another string value. Then it loops through that string instead of the one read by main(), and only checks the 1st char before exiting. If the char is a digit, checkInput() returns true, and main() exits. Otherwise, checkInput() prompts the user to type in yet another char and then returns false, which then causes main() to prompt the user to type in yet another char. checkInput() does not actually loop through an entire string at all, and does no have any handling for the - character.
Try this instead:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <cctype>
#include <limits>
using namespace std;
bool checkInput(const string &);
int main()
{
string userInput;
cout << "Please enter a numeric value : ";
do
{
cin >> userInput;
if (checkInput(userInput))
break;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Please enter a valid numeric value: ";
}
while (true);
cout << "\nYour input " << userInput << " is a valid numeric input." << endl;
system("pause");
return 0;
}
bool checkInput(const string &input)
{
if (input.empty())
return false;
string::size_type i = 0;
if (input[0] == '-')
{
++i;
if (i == input.length())
return false;
}
do
{
if (!isdigit(input[i]))
return false;
}
while (++i < input.length());
return true;
}
However, the best way to handle this situation is to simply not allow the user to enter non-integer values to begin with. operator>> has overloads for reading integer values, both signed and unsigned types. In this case, reading int values will suffice. Let cin do all of the input validation for you:
#include "stdafx.h"
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int userInput;
cout << "Please enter a numeric value : ";
while (!(cin >> userInput))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Please enter a valid numeric value: ";
}
cout << "\nYour input " << userInput << " is a valid numeric input." << endl;
system("pause");
return 0;
}

C++: How to solve a char bug in a do while loop?

Can you help me to solve this bug?
It is a game where you need to guess the hidden number. The problem is that when I enter a character that isn't an integer number, the program outputs a message infinitely,
Here is bug message if i enter a char
but I would like to make this program to output only message "You haven't entered a number, please try again".
Here is a normal execution
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
using namespace std;
main(){
int a,b;
char c;
START:
system("cls");
srand (time(NULL));
a = rand() % 100 + 1;
cout << "Guess The hidden Number Between 1 and 100" << endl;
do {
cout << endl<<" Enter Any Number : "; cin>>b;
if(b>100||b<1) cout<<" Try another number that is between 1 and 100!!!";
else {
if (b>a)
cout <<" =>Too Big";
else if (b<a)
cout <<" =>Too Small";
else if (b==a) {
cout<<" =>You've Guess It!!!"<<endl;
break;
}
}
}
while (b != a);
cout << endl << "Press 'q' to start. Press else to close ";
c = getch();
if (c=='q'||c=='Q') goto START;
}
Your code int b; cin >> b; will try to read integer and will fail if where is no integer in the stream. Fail bit of cin will be set, you can check it either with if(cin.fail()) {} or just if(cin) {}. So, you need to extract junk input from cin before the next read. You can reach this effect by actually reading anything from cin and then trying to convert it to an integer.
#include <iostream>
#include <string>
using namespace std;
int main() {
int b;
string s;
do {
cout << endl << "Enter Any Number: ";
getline(cin, s);
try {
b = stoi(s);
cout << "Your code goes here." << endl;
}
catch (invalid_argument& ex) {}
catch (out_of_range& ex) {}
} while (true);
}
Something like this
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
int main() {
int b;
char s[1];
do {
cout << endl << "Enter Any Number: ";
gets(s);
try {
b = atoi(s);
cout << "Your code goes here." << endl;
}
catch (invalid_argument& ex) {}
catch (out_of_range& ex) {}
} while (true);
}
What you are seeing is the stream breaking. When you do std::cin << intNum; with a non-integer input, the data types are non-compatible, so it doesn't know what to do. To "fix" the stream, you need to clear the stream of it's error state using std::cin.clear() then the standard practice is to ignore the rest of the line to avoid other invalid input. A code snippet would look something like this:
while(std::cin.fail())
{
std::cin.clear();
std::cin.ignore(1000000, '\n');
}
This will check if the stream is broken, clear the flag so it can take input again, then clear out the next 1000000 characters or to the next \n, whichever comes first.

std::cin doesn't throw an exception on bad input

I am just trying to write a simple program that reads from cin, then validates that the input is an integer. If it does, I will break out of my while loop. If not, I will ask the user for input again.
My program compiles and runs just fine, which is great. But it doesn't prompt for new input if I enter a non numeric value. What gives?
#include <iostream>
using namespace std;
int main() {
bool flag = true;
int input;
while(flag){
try{
cout << "Please enter an integral value \n";
cin >> input;
if (!( input % 1 ) || input == 0){ break; }
}
catch (exception& e)
{ cout << "Please enter an integral value";
flag = true;}
}
cout << input;
return 0;
}
C++ iostreams don't use exceptions unless you tell them to, with cin.exceptions( /* conditions for exception */ ).
But your code flow is more natural without the exception. Just do if (!(cin >> input)), etc.
Also remember to clear the failure bit before trying again.
The whole thing can be:
int main()
{
int input;
do {
cout << "Please enter an integral value \n";
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} while(!(cin >> input));
cout << input;
return 0;
}
Don't use using namespace std; Instead import what you need.
It's better to do input a line at a time. This makes behavior much more intuitive if you have multiple words on one line, or if you press enter before typing anything.
#include <iostream>
#include <sstream>
#include <string>
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::flush;
using std::getline;
using std::istringstream;
using std::string;
int main() {
int input;
while (true)
{
cout << "Please enter an integral value: " << flush;
string line;
if (!getline(cin, line)) {
cerr << "input failed" << endl;
return 1;
}
istringstream line_stream(line);
char extra;
if (line_stream >> input && !(line_stream >> extra))
break;
}
cout << input << endl;
return 0;
}

C++ cin.fail() question

When running the following code and enter a number, it works fine.
But when entering a letter, the program enters an infinite loop, displaying "Enter a number (0 to exit): cin failed."
My intent was to handle the cin fail case and prompt the user again.
int number;
do{
cout << "Enter a number (0 to exit): ";
cin >> number;
if(cin.fail()){
cout << "cin failed." << endl;
cin.clear();
}else{
cout << "cin succeeded, " << number << " entered." << endl;
}
}while(number != 0);
You need to clear the line from cin, using cin.ignore, in addition to clearing the stream state (which is what cin.clear does).
I have several utility functions to make this easier (you'll be interested in clearline in particular, which clears the stream state and the current line) and almost an exact example of what you want.
Your code, more or less, using my clearline:
#include "clinput.hpp" // move my file to a location it can be used from
int main() {
using namespace std;
while (true) {
cout << "Enter a number (0 to exit): ";
int number;
if (cin >> number) {
cout << "Read " << number << '\n';
if (number == 0) {
break;
}
}
else {
if (cin.eof()) { // tested only *after* failed state
cerr << "Input failed due to EOF, exiting.\n";
return 1;
}
cerr << "Input failed, try again.\n";
clearline(cin); // "cin >> clearline" is identical
}
}
return 0;
}
There is still a potential issue here (fixed in my clinput_loop.cpp with blankline), with leaving input in the buffer that will screw up later IO (see "42 abc" in the sample session). Extracting the above code into a separate and self-contained function is left as an exercise for the reader, but here's a skeleton:
template<class Type, class Ch, class ChTr>
Type read(std::basic_istream<Ch,ChTr>& stream, Ch const* prompt) {
Type value;
// *try input here*
if (could_not_get_input or more_of_line_left) {
throw std::runtime_error("...");
}
return value;
}
template<class Type, class Ch, class ChTr>
void read_into(
Type& value,
std::basic_istream<Ch,ChTr>& stream,
Ch const* prompt
) {
value = read<Type>(stream, prompt);
}
Example use:
int n;
try {
read_into(n, std::cin, "Enter a number: ");
}
catch (std::runtime_error& e) {
//...
raise;
}
cout << "Read " << n << '\n';
clearline function extracted for posterity, in case above links ever break (and slightly changed to make self-contained):
#include <istream>
#include <limits>
template<class C, class T>
std::basic_istream<C,T>& clearline(std::basic_istream<C,T>& s) {
s.clear();
s.ignore(std::numeric_limits<std::streamsize>::max(), s.widen('\n'))
return s;
}
The template stuff is a bit confusing if you're not used to it, but it's not hard:
std::istream is a typedef of std::basic_istream<char, std::char_traits<char> >
std::wistream is a typedef of std::basic_istream<wchar_t, std::char_traits<wchar_t> >
widen allows '\n' to become L'\n' as appropriate
this code works for both of the common char and wchar_t cases, but also any compatible instantiation of basic_istream
it's written to be called as clearline(stream) or stream >> clearline, compare to other manipulators like std::endl, std::ws, or std::boolalpha
This is probably what you intended to do:
#include <iostream>
using namespace std;
int main ()
{
int i;
do {
if (cin.fail())
{
cin.ignore(255);
cin.clear();
}
cout << "Please enter an integer value: ";
cin >> i;
} while ( cin.fail() );
cout << "The value you entered is " << i;
return 0;
}
This is simple example of cin.fail()
It will process input until a valid integer value is provided
#include <iostream>
using namespace std;
int main()
{
int j;
int i;
i = 0;
while (1) {
i++;
cin >> j;
if (cin.fail()) return 0;
cout << "Integer " << i << ": " << j << endl;
}
}
Input:
42 51 85 hello 85
Output:
Integer 1: 42
Integer 2: 51
Integer 3: 85