So I'm having some problems when using cin and switch statements.
First, the program prompts for an int:
cout << "How many registers would you like to use?: ";
cin >> kassor;
Later on, the user is asked to make a choice:
cout << endl << "Press \"S\" to run the queue simulator and/or make a timestep." << endl;
cout << "Press \"Q\" to quit." << endl << endl;
cout << "Choice: ";
cin >> choice;
switch (choice)
{
case 's':
case 'S':
{
cout << "test";
nya = newCustomers();
break;
}
case 'q':
case 'Q':
{
return 0;
}
}
Here, the 'q' option works fine, but the 's' option does not. It 'hangs', as if still waiting for input. I have tried various cin.ignore() and such, but to no avail.
What puzzles me is that
switch (choice)
{
case 's':
case 'S':
{
cout << "test";
nya = newCustomers();
break;
Gives nothing, but the following:
switch (choice)
{
case 's':
case 'S':
{
cout << "test";
cin.ignore(1024, '\n');
nya = newCustomers();
break;
outputs 'test'.
My main question here is: Is the problem cin or something in the case: s ?
Thank's in advance :
It looks like the function newCustomers is getting hung up on a stray character or two after the input to choice. That would explain why the ignore call "fixes" the problem, and it's the solution suggested in the comment by #TheBuzzSaw.
To see this more clearly, change
cout << "test";
to
cout << "test\n";
or to
cout << "test" << std::endl;
On some systems the console is line-buffered, so you won't see any output until the program writes a newline. Inserting endl flushes the output buffer, so you should see the message even if subsequent code hangs. Or change it to:
cerr << "test\n";
cerr is more aggressive about flushing buffers, precisely because it's used for error output that you don't want to miss.
Short Answer:
I believe cin is failing somewhere or it is the cause of unexpected behavior
I cannot pinpoint it without more code.
Edit: I cannot post a comment on your post, so I figured I would post here. The "hanging" could be an infinite loop. If you are doing something like what I am doing and looping to get input and fail to clear the error bits cin will constantly fail. If you are not cout'ing something each time you ask for input it could just be quietly sitting there looping through that input-gathering function. Put breakpoints in all of your loops and step through with the debugger to verify none of your loops are infinite looping.
Try adding a std::cin.clear(); before the .ignore() in your second test case. See if that stops your hanging.
Explanation:
cin can fail. This can cause weird behavior. A common way for it to fail is if you are reading into an integer and you get character input. Once cin fails it sets a fail bit and from then on, cin does not behave like you would expect.
I would recommend not using a bare cin >> choice, because it can fail and you wont know it. I would abstract this out to a method that gets the proper input you want.
I personally keep a tiny utility library(.h) and .cpp around to include in projects where I am using common functionality I have already coded.
I have a readIntBetween() function which accepts 2 integers and reads from standard input an integer between those two numbers. If the user does not provide the right input (integer over or under bounds, or input containing a character) I ask them to re-enter the input.
In this function I make sure to clear the fail bits when I have detected a failure, and I ignore something like 200 characters to "flush" it out.
Here is the code to my readIntBetween function. I hope it helps you diagnose your error and fix it:
int readIntBetween(int lower, int upper, std::string prompt)
{
bool goodVal = false;
int value = -1;
do
{
std::cout << prompt ;
std::cin >> value;
if ( value >= lower && value <= upper)//check to make sure the value is in between upper and lower
goodVal = true;
else
{
if(std::cin.fail())
{
std::cout << "\tError - invalid format for integer number" << std::endl;
//clear all status bit including fail bit
std::cin.clear();
//flush input buffer to discard invalid input
std::cin.ignore(1000, '\n');
}
else
std::cout << "Value is not valid, must be between " << lower<<" and "<<upper<<"."<<std::endl;
}
}while(!goodVal);
return value;
}
If your cin is being used inside a loop, I recommend a different approach.
char buffer[64];
cin.getline(buffer, 64);
char choice = buffer[0];
switch (choice)
{
...
}
It is possible your cin is not being reset, and any extraneous characters are being fed into the subsequent requests for input. Grab more input and only process its first character.
Related
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
}
I have written a program with several menus within it. I am now debugging the program and I wanted to include some input validation in the menu choices. However, for some reason, when it detects a wrong input it goes back to the beginning of the function with a goto statement (I know, bad practice :\) and It asks the user for a new input, but even if the input is right, it goes back to the case for non allowed inputs (default) no matter what. Does anyone have any idea of what's going on?
NOTE:
select_variable_check(vector<int> , int) is a function that checks if the value entered has been entered before if that is of any relevance, although I don't think it has anything to do with it.
void select(vector<int>&select_control) {
char select;
choices:
cin >> select;
int selectint = select;
bool check = select_variable_check(select_control, selectint);
switch (select) {
case ('1','2','3','4','5','6','7','8','9','10'):
if (check == false) {
string city = city_selection(selectint);
double xcoor = xcoor_selection(selectint);
double ycoor = ycoor_selection(selectint);
cout << "\n" << city << "\n";
select_control.push_back(selectint);
cout << "\n Enter next city: ";
cin >> select;
selectint = select;
}
else {
cout << "You have already selected that city, please select another one ";
cin >> select;
}
break;
case '99': {
cout << "TERMINATING" << endl;
Sleep(3000);
exit(0);
break;
}
case '100': {
cout << "input complete" << endl;
break;
}
default: {
cout << "not a valid value, please try again" << endl;
goto choices;
break;
}
}
The value of ('1','2','3','4','5','6','7','8','9','10') is '10', so that's the only value that will trigger that first case statement. The right way to write this is:
case '1':
case '2':
case '3':
...
Even with this change, though, '10' is a peculiar kind of character, and almost certainly not the right thing here.
Your code boils down to
start:
get_input
process_input
if good do something
else go to start
end:
Now when you enter bad input it goes back to start. Your input operation will fail again as the input stream is still in an error state so you do not get new input and since you have bad input you go back to start. To stop this loop you need to clear out the error flags on the stream and remove any input still in the buffer. That will make you default case look like
default: {
cout << "not a valid value, please try again" << endl;
cin.clear(); // removes error flags
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // flushes input buffer
goto choices;
break;
}
You will need to #include <limits> to use cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
I've been searching and trying different things for an hour and can't figure this out. Why doesn't my default work? If I enter 1-4, the output is as expected. However, if I enter any other number or letter, nothing is displayed. I would like the default to display if I enter any other number or letter.
RESOLVED: It was my compiler. Going to use Visual Studio only from now on. (VS didn't show my default at first because I was using it incorrectly.) Thanks to everyone for your responses.
My code:
int main()
{
int num;
cout << "Please enter the code stamped on the storage drive (1-4): ";
cin >> num;
switch (num)
{
case 1:
cout << "The code you entered was 1; therefore, the storage capacity is 2GB." << endl;
break;
case 2:
cout << "The code you entered was 2; therefore, the storage capacity is 4GB." << endl;
break;
case 3:
cout << "The code you entered was 3; therefore, the storage capacity is 16GB." << endl;
break;
case 4:
cout << "The code you entered was 4; therefore, the storage capacity is 32GB." << endl;
break;
default:
cout << "Invalid selection - Please input 1 to 4 only.";
break;
} //end of switch
return 0;
}
The default is working (I've tested it), subject to the following caveats.
First of all, the way your code is structured, you have to enter something. If you just press Enter, nothing will happens because cin >> num will continue waiting for a number.
Secondly, when you enter anything that's not a number, cin >> num fails and leaves num uninitialized. This leads to undefined behaviour in the switch.
You should initialize num (say to 0 or another invalid value) and/or check whether cin >> num has succeeded:
if (cin >> num) {
// the read has succeeded
} else {
// the read has failed
}
Try adding either a '\n' to the end of your default message or a << endl.
Looks like the text from the default is waiting to be flushed.
You could also add a cout.flush(); before the end of your program.
I know this is pointless saying anything as this was a while ago, but for those who have a similar problem look at your code.... case 1: it should instead case '1': the same applies for every other case, then your switch statement will work
After this question I figured out that using char as input will avoid the infinite loop caused by typing characters for input which is using int. But now I had met another problem.
When I typed the code below:
#include <iostream>
void language();
int main() {
language();
}
void language() {
char choice;
// Ask user for something and input
std::cout << "Press 1 to exit the program\n\n";
std::cin >> choice;
// Getting user's input and run the code below and find for specific words
switch(choice) {
case '1':
std::cout << "\n\nEnding program...";
return 0;
break;
default:
std::cout << "\n\nPlease type the specific number.\n\n";
language();
break;
}
}
When I compile it I didn't get any errors or warnings. But when I type 12 or similar word with 1 at first, the program will be ended.
And before answering me, I still learning C++. (By the way I don't think I really need to say this?) And because this I didn't know how to solve this. What's happening to my code?
As you want a char from the input, std::cin will just get the first character you type in the input and assign to choice. It will ignore the following characters.
That is, you will enter in the first case of your switch/case condition and return.
It depends on what are the inputs you expect from the user. If you expect only numbers, I suggest you to use an int :
#include <limits> // needed for std::numeric_limits
void language() {
int choice;
// ^^^^
// Ask user for something and input
std::cout << "Press 1 to exit the program\n\n";
std::cin >> choice;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Getting user's input and run the code below and find for specific words
switch(choice) {
case 1:
std::cout << "\n\nEnding program...";
break;
default:
std::cout << "\n\nPlease type the specific number.\n\n";
language();
break;
}
}
Working live example.
Your code is exiting when you enter input starting with character 1.
You want the choice as string, not char since char only contains one character. Also you don't need break after the return statement
char choice;
will just receive a single character from standard input.
so all digits starting with 1 will end your program
instead use int choice; and change case to case 1:
#include<limits>
//...
int choice;
//...
std::cout << "Press 1 to exit the program\n\n";
while(true)
{
if (std::cin >> choice)
break ;
else {
std::cout<<"Not an integer !"<<std::endl;
std::cin.clear() ;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),
'\n') ;
}
}
switch(choice) {
case 1:
//...
break;
default:
std::cout << "\n\nPlease type the specific number.\n\n";
language();
break;
}
So i'm making a menu in a simple console app.
My code is pretty much: (LINKS TO ACTUAL CODE AT THE BOTTOM!)
int input;
bool LOOPING = true;
while(LOOPING)
{
cout << "Select an option:\n";
cout << "1 - option 1\n";
cout << "2 - option 2\n";
cout << "3 - option 3\n";
cout << "4 - option 4\n>";
cin >> input;
switch(input) {
case 1:
game();
break;
case 2:
game();
break;
case 3:
game();
break;
case 4:
game();
break;
default:
cout << "ERROR: invalid input!\nPlease enter in a number!\n\n";
break;
}
}
// rest of app...
My problem is, the program just goes into a constant loop of text! Why is this happening? Why does default: not stop that from happening and how do i stop this from occuring?
Thanks in advance!
EDIT: asked for real code.
http://pastie.org/2415852
http://pastie.org/2415854
http://pastie.org/2415855
Your code is looping infinitely because you never set LOOPING to false. In the real code you only set it to false when the user chooses to exit, which will never happen because the user is not able to enter input anymore after he inputs a non-number for the first time.
The reason that it doesn't keep asking you for input after you entered a character is that >> does not consume invalid input. I.e. if >> is supposed to write into an int, but what the user enters is not a valid int, it will not write to the int, but it will also not remove the user input from the stream (instead it will simply set cin's error flag, which you should check).
The input will stay in the stream until you write it somewhere else or discard it. Until you do that every subsequent attempt to read an int will fail because the invalid input is still in the stream.