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.
Related
So I have just learnt input validation however I ran into a problem. I'm forcing the user to enter a number and not a string which works, however if the user enter a number (one that is included in the switch case) and a string then the program crashes. Any tips on what to change so the validation works on everything?
int menu(double pi) //menu for choosing a shape
{
int choice = 0;
cout << "Please select what you wish to calculate:\n\n1 - Area of a Circle\n\n2 - Circumference of a Circle\n\n3 - Area of a Rectangle\n\n4 - Area of a Triangle\n\n5 - Volume of a Cuboid\n\n ";
while (!(cin >> choice))
{
cout << "Invalid input, please enter a number of 1-5\n\n";
cin.clear();
cin.ignore(100, '\n');
}
system("CLS");
switch (choice) //switch case for each shape
{
case 1:
circleArea(pi);
break;
case 2:
circleCircum(pi);
break;
case 3:
rectanArea();
break;
case 4:
triangArea();
break;
case 5:
cubVol();
break;
default:
cout << "Invalid input! Please try again.\n\n";
break;
}
return 0;
}
The issue with using
cin >> choice
When inputting a number is that >> will stop at the first non-numeric input and as long as there was numeric input to begin with it will treat it as a valid read. That means things like 2L, 2.0, and -1T are all valid integer inputs as far as cin is concerned. It just leaves the invalid part in the stream. It is this remaining steam input that messes up the program on the next input operation.
One way to fix this is to read the input into a std::string using getline and then parse the string to make sure it contains valid input. If you want to get a int for instance the
int choice;
std::string input;
std::size_t pos;
do
{
std::cout << "Enter Choice: ";
std::getline(cin,input);
choice = stoi(input, &pos);
} while(pos != input.size());
This makes sure that you read in everything up to the pressing enter into input and that you only stop the loop once everything entered can be converted to a valid int.
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 am using Microsoft Visual studio 2013
I currently have this switch statement:
switch (option)
{
case 1:
getline(cin, newname);
cout << "What would you like your new username to be?\nName: ";
getline(cin, newname);
name = newname;
cout << "\nYour username is now '" << name << "' with your balance being $" << balance << "\n";
options();
break;
case 2:
cout << "\nOpenning cheat menu\n";
cheats();
break;
default:
cout << "\nExitting to main title...\n";
title();
break;
}
you can just ignore the case 2 and default, just showing so you know that those cases work. Case 2 and default work perfectly fine but case 1 is acting weird. As you can see on case 1 I have two getline(cin, newname); You may think I should only have one, but for some reason I need two for this code to function correctly.
If I only have one of these the code jumps past the input the user should give. If I have two it works normally.
I have asked someone this and they do not understand either, so therefore: Why does this work.
Apparently you have leftover input including a newline, in the input buffer of cin. That happens when you use other input operations than getline. They generally don't consume everything in the input buffer.
Instead of the extra getline you can use ignore, but better, do that at the place where you earlier do the inputting.
I think a similar problem has been posted here.
You need to flush the newline with cin.ignore() or cin.sync().
The first call also seems misplaced...
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
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.