C++ Switch loop error - c++

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.

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

Hi I want user to enter 5 numbers and then output the sum in the end

I have used a loop for that:
int number1;
int sum=0;
for(int i =1; i<6; i++){
cout<<"Enter number:\n";
cin>>number1;
sum+=number1;
}
cout<<sum;
cout<<"Total Sum is = "<<sum<<"\n";
return 0;
}
My question is how can I print first statement like this ...
"Enter first number"
Enter Second number" and so on
Whenever you are reading numbers (or any value for that matter), you must check the stream-state (see: std::basic_istream State Functions). You have four stream states you must test following every input:
.bad() or .eof(). If badbit is set an unrecoverable error occurred, and if eofbit is set, there is nothing more to read (you can combine both into a single test that exits if either are set)
.fail() is set when a read error occurs, such as the user entering "FIVE" instead of 5 where integer input is expected. You handle failbit being set by calling .clear() to clear failbit and then call ignore() to empty the characters causing the failure before your next read attempt, and finally
.good() - valid input was received from the user, you can proceed to the next input.
By validating your input here, you can Require the user provide 5 valid integer values for you to sum. Do not use a for loop, instead use a while (or do .. while();) and only increment your counter when good input is received.
Putting that altogether, you can do:
#include <iostream>
#include <limits>
int main (void) {
int number = 0,
sum = 0;
const char *label[] = { "first", "second", "third", "fourth", "fifth" };
while (number < 5) /* loop continually until 5 int entered */
{
int tmp; /* temporary int to fill with user-input */
std::cout << "\nenter " << label[number] << " number: ";
if (! (std::cin >> tmp) ) { /* check stream state */
/* if eof() or bad() exit */
if (std::cin.eof() || std::cin.bad()) {
std::cerr << " (user canceled or unreconverable error)\n";
return 1;
}
else if (std::cin.fail()) { /* if failbit */
std::cerr << " error: invalid input.\n";
std::cin.clear(); /* clear failbit */
/* extract any characters that remain unread */
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
else { /* on succesful read of int, add to sum, increment number */
sum += tmp;
number++;
}
}
std::cout << "\nsum: " << sum << '\n';
}
Now your code will gracefully handle an invalid input without exiting just because a stray character was entered.
Example Use/Output
When you write an input routine, go try and break it. Enter invalid data and make sure you handle all error cases correctly. If something doesn't work right, go fix it. Repeat until you input routine can handle all corner-cases as well as the cat stepping on the keyboard:
$ ./bin/sumintlabel
enter first number: 3
enter second number: four five six seven!!
error: invalid input.
enter second number: 4
enter third number: 5
enter fourth number: 6
enter fifth number: 7
sum: 25
Form good habits now regarding handling input, it will pay dividends for the rest of your programming career. Let me know if you have questions.
if you need to print the words "first"... untill "fifth" then I'd do it like this:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int number1;
int sum=0;
string positions[5] = {"first", "second", "third", "fourth", "fifth"};
for(int i = 0; i<5; i++){
cout<<"Enter the " << positions[i] << " number:" << endl;
cin>>number1;
sum+=number1;
}
cout<<"Total Sum is = "<<sum<<"\n";
return 0;
}
I used an array of strings to display the words and changed the for loop to start at 0 so that we can go through the array positions and add the 5 numbers as well. If you just want to use: 1st, 2nd, 3rd... then you could change the for loop to what it was and do:
cout<<"Enter the " << i << "st" << " number:" << endl;
But for this you would have to use the if statement to print the right endings("st", "rd", "nd"). I think it would take longer for it to run but its miliseconds so we wouldn't even notice hahaha.
Hope it helped :)
You can use switch():
#include <iostream>
using std::cin;
using std::cout;
using std::string;
int main() {
int number1;
int sum = 0;
for(int i = 1; i < 6; i++) {
string num;
switch(i) {
case 1:
num = "first";
break;
case 2:
num = "second";
break;
//and 3 4 5 like this
}
cout << "Enter " << num << " number:\n";
cin >> number1;
sum += number1;
}
cout << "Total Sum is = " << sum << "\n";
return 0;
}
or you can use struct or containers like vector (in fact you have to use containers if you want to get a huge number of data.)

C++ Cin ignores non-integers? [duplicate]

This question already has answers here:
Why do I get an infinite loop if I enter a letter rather than a number? [duplicate]
(4 answers)
Closed 5 years ago.
I have a question about c++. I've been searching for an answer and have found nothing that will fix my code. So I decided to ask myself. My problem is, that I made this little program that will output the day of the week, so if the user inputs 1, it will output the 1st day of the week (Sunday or Monday, depends on where you live) and so on and so forth. However, if the user inputs for example, 8, then the program will output "Please choose a number between 1 and 7!"
However, my problem is that when the user inputs a character or random word, it will loop "Please choose a number between 1 and 7!" forever.
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
int main() {
int input;
do {
cin >> input;
switch (input) {
case 1:
cout << "Sunday" << endl;
break;
case 2:
cout << "Monday" << endl;
break;
case 3:
cout << "Tuesday" << endl;
break;
case 4:
cout << "Wednesday" << endl;
break;
case 5:
cout << "Thursday" << endl;
break;
case 6:
cout << "Friday" << endl;
break;
case 7:
cout << "Saturday" << endl;
break;
default:
cout << "Please choose a number between 1 and 7!" << endl; // if user chooses a number not from 1-7 output this. But if input is not an int and for example "a", it will loop this forever.
break;
}
} while (true);
return 0;
}
Statement cin >> input may fail, e.g. if a user inputs something that cannot be converted to an integral value, or if the stream reaches EOF (e.g. CTRL-D or CTRL-Z in standard input).
If cin >> input fails, two things happen: First, an error state is set, indicating the type of failure. Second, the expression returns false, indicating that no value has been written to input.
So you should always check the result of cin >> ... before going ahead. And, if you detect an invalid input, you will have to reset the error flag (using cin.clear()) before reading in again, and you might want to skip the invalid input (using cin.ignore(...)) in order to avoid reading in the same (invalid) input again and again:
int main() {
int input;
while (true) {
while (!(cin >> input)) {
if (cin.eof()) {
cout << "user terminated input." << endl;
return 0;
}
cout << "invalid input (not a number); try again." << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
}
// from here on, you may rely that the user has input a number.
cout << input;
// ... your code goes here
}
return 0 ;
}
Note that you should specifically allow the program to exit when reaching EOF. Otherwise, you may run into an infinite loop when you pass a file with invalid content as input to your program (e.g. by myProgram < input.txt).
IO operations sets flags about current state of stream.
These are important flags, what you should care about if reading input
badbit - Read/writing error on i/o operation
failbit - Logical error on i/o operation
eofbit - End-of-File reached on input operation
If you pass an character to stream which expects int (pass an wrong datatype overall, which cannot be converted to type that cin expects), the failbit is set.
Thats the reason why you got into infinite loop after inserting wrong input. failbit was set and cin wasn't cleared, so next reading operation failed as well and again and again.
The thing to do is unset failbit and discard the bad input from the input buffer using ignore.
std::cin.clear(); // without params clears flags
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Clear input buffer
std::cin.fail() will tell you if failbit is set (wrong IO operation).
int input;
cin >> input;
while (! cin.fail())
{
// Process data
cin >> input;
}
and std::cin.eof() will tell you if eofbit is set, reach EOF (CTRL+D/+Z on std input)
if (cin.eof())
{
// End of file (input) reached
// Terminate reading
}

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.

Not handling user input correctly

So, this program I am working on is not handling incorrect user input the way I want it to. The user should only be able to enter a 3-digit number for use later in a HotelRoom object constructor. Unfortunately, my instructor doesn't allow the use of string objects in his class (otherwise, I wouldn't have any problems, I think). Also, I am passing the roomNumBuffer to the constructor to create a const char pointer. I am currently using the iostream, iomanip, string.h, and limits preprocessor directives. The problem occurs after trying to enter too many chars for the roomNumBuffer. The following screenshot shows what happens:
The relevant code for this problem follows:
cout << endl << "Please enter the 3-digit room number: ";
do { //loop to check user input
badInput = false;
cin.width(4);
cin >> roomNumBuffer;
for(int x = 0; x < 3; x++) {
if(!isdigit(roomNumBuffer[x])) { //check all chars entered are digits
badInput = true;
}
}
if(badInput) {
cout << endl << "You did not enter a valid room number. Please try again: ";
}
cin.get(); //Trying to dum- any extra chars the user might enter
} while(badInput);
for(;;) { //Infinite loop broken when correct input obtained
cin.get(); //Same as above
cout << "Please enter the room capacity: ";
if(cin >> roomCap) {
break;
} else {
cout << "Please enter a valid integer" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
for(;;) { //Infinite loop broken when correct input obtained
cout << "Please enter the nightly room rate: ";
if(cin >> roomRt) {
break;
} else {
cout << "Please enter a valid rate" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
Any ideas would be greatly appreciated. Thanks in advance.
Read an integer and test whether it's in the desired range:
int n;
if (!(std::cin >> n && n >= 100 && n < 1000))
{
/* input error! */
}
Although Kerrek SB provide an approach how to address the problem, just to explain what when wrong with your approach: the integer array could successfully be read. The stream was in good state but you didn't reach a space. That is, to use your approach, you'd need to also test that the character following the last digit, i.e., the next character in the stream, is a whitespace of some sort:
if (std::isspace(std::cin.peek())) {
// deal with funny input
}
It seems the error recovery for the first value isn't quite right, though. You probably also want to ignore() all characters until the end of the line.