Problem with C++ understanding chars within float input - c++

#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
}
}
}

Related

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.

C++ : check whether an input is a number

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

C++ Switch loop error

I'm a C++ beginner. My problem is, if the user accidentally inputs a letter, the program will send the error message and it wont loop back. This is my code:
#include <string>
#include <iostream>
using namespace std;
int main()
{
int q;
A:
cout << "[1] Name";
cout << "\n[2] Address";
cout << "\nEnter your choice: ";
cin >> q;
switch (q)
{
case 1:
cout << "XXXXXXXXXX" << endl;
break;
case 2:
cout << "XXXXXXXXXX" << endl;
break;
default:
cout << "Error! Enter only numbers from 1 - 2" << endl;
goto A;
}
return 0;
}
Output was :
[1] Name
[2] Address
Enter your choice: x
Error! Enter only numbers from 1 - 2
[1] Name
[2] Address
Enter your choice: Error! Enter only numbers from 1 - 2
[1] Name
[2] Address
Enter your choice: Error! Enter only numbers from 1 - 2
...
It should be like this,
[1] Name
[2] Address
Enter your choice: 8
Error! Enter only numbers from 1 - 2
[1] Name
[2] Address
Enter your choice:
If user enters a wrong number, it loops back, and if the user enters a letter, it should loop back like this too.
What is wrong?
The problem is that when you enter a non-integer input, the input is not actually extracted from the input-buffer, so each iteration of the loop you will attempt to read the same input over and over again.
What you need to do is rely on the fact that illegal input (non-integer in your case) will cause the stream to set its failbit, that the input operator >> function returns a reference to the stream, and that the state of a stream can be checked in a simple boolean condition.
Something like
if (std::cin >> q)
{
// Successfully read an integer
}
else
{
// Failed to read an integer, input is probably something else
// Clear the failbit
std::cin.clear();
// Explicitly ignore the rest of the line
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Output error message
}
The above code can be put in a loop that is exited by setting a boolean variable in the switch-cases for valid integers.
References:
std::ios::clear
std::istream::ignore.
std::numeric_limits
Since the input might not be numeric, let's allow for that. I'm assuming the use of System.String -- if it isn't, modifying this snippet is left as an exercise for the student.
using System;
String entry = "";
int entry_val = 0;
bool valid = false;
do
{
//menu goes here
cin >> entry;
if ( entry >= "1" && entry <= "2" )
{
entry_val = entry.ToInt();
valid = true;
}
else
{
cout << "Error! Enter only numbers from 1 - 2" << endl;
}
while (valid == false)
...
continue with the switch() {} block.

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.

Failed Input help, Int and Char, C++

I am trying to determine if the user enters something other than a character, and specifically, that they only enter m or s. See code below.
Note:
filingStatus is a char
do
{
cout << "Please enter your filing status (s for single, m for married)" << '\n';
cin >> filingStatus;
if (cin.fail())
{
cin.clear();
dataTest = 1;
cout << "Error, please enter a valid input!" << '\n';
double dummyDouble;
cin >> dummyDouble;
if (cin.fail())
{
cin.clear();
cin >> dummyString;
}
}
else
{
if (filingStatus == 'm' || filingStatus == 's')
{
dataTest = 0;
}
else
{
cout << "Error, please enter either m or s!" << '\n';
dataTest = 1;
}
}
} while (dataTest == 1);
Here is the problem, if I enter 1000 for example, the input doesn't fail. It instead stores the 1 in the char, and since 1 is neither m or S, it loops again, then it puts the 0, loops again, puts another 0, etc.
My understanding was it would fail when it sees that a integer is being stored in a char, but obviously it isn't failing.
My question is:
Why isn't the input failing? How can I change it so if someone enters a string, or number that it fails?
The input isn't failing, because '1' is a character. Digits are a subset of characters.
Read into a std::string. Then test whether that string consists of a single character from your desired range.
Note however, that reading into a string using >> stops at the first white space. To prevent this and read the whole line instead, read using std::getline().
I am assuming that fillingStatus is of char type.
Now even if you enter a numeral say '1' or '0', it is read as a char. Hence cin does not fail. It just keeps on looping as per your code.
Also, while reading an invalid char, you should be careful of clearing the input buffer because the return character '\n' stays along with other characters in the input buffer.
I would do it something like the following:
while ( !(cin >> fillingStatus) || (filingStatus != 'm' && filingStatus != 's') ) {
cout << "Error, please enter either m or s!" << '\n'; // error message
cin.clear(); // clear the error flag
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // ignore all invalid previous input
}
One way could be to change the fillingStatus to string and get only the first character of that string and see if it fails or not.
Alternatively, there used to be a method for getting a character input, getche() I think (it has been many years since I worked in C++ so don't exactly recall)...you maybe able to use that too.
Thanks
Since you are only reading the input one character at a time, your are essentially unable to tell that the user has input more and it is being held until you read more from the input stream.
Using a string to read a line of data at a time and having the program react to that string as a whole will solve your problem.
std::string filingStatus ;
while(!(cin >> filingStatus ) || ( filingStatus != "m" && filingStatus != "f") )
{
cin.clear();
std::cout << "Error, please enter either m or s!" << '\n';
};