Stuck in loop within a function (C++) - c++

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')

Related

C++: Telling user to input A, B, or C but what if they enter a different character?

As the title suggests, I have a working program for when a user inputs A B or C. My professor has said that we have not gone over repetition yet so we just need to put in a line of code that returns something like "Please enter either A B or C" when the user enters any other character but I am having trouble figuring out how to do this. Any help will be very appreciated. I'll post a file of the code I have now.
https://docs.google.com/document/d/1EVxLPtOsBbdmCCt0LwUDYkqgySg8bSm3w_d_CAcGW6g/edit?usp=sharing
Here is a common stencil for processing menus:
bool invalid_selection = true;
while (invalid_selection)
{
// Output the menu with choices
// ...
char choice;
std::cin >> choice;
choice = std::toupper(choice);
switch (choice)
{
case 'A':
do_something;
break;
// ... other choices ...
default:
std::cout << "Invalid choice.";
}
if (choice == quit_character)
{
break; // exit out of the loop
}
}
There are many other alternatives. For example, one is a do-while loop.
If you don't know about switch, use your if-else-if ladder. The final else clause is equivalent to the default case.
EDIT: It'd be even better to use a std::string as a buffer to prevent receiving multiple errors from this if the user inputs more than one char.
The best way to handle this would probably be a simple do... while nested switch statement:
#include <string>
bool repeat = true;
do {
std::string buffer;
cout << "Which plan do you want to use?" << endl;
cin >> buffer;
// check if the user entered only one character
if (buffer.length() > 1) {
cout << "Invalid Input" << endl;
continue;
}
plan = buffer[0];
switch(plan) {
case 'A':
// do things
repeat = false;
break;
case 'B':
// do things
repeat = false;
break;
case 'C':
// do things
repeat = false;
break;
default:
cout << "Invalid input, please try again." << endl;
break;
} while (repeat);
This keeps asking the user for which plan they want to use, until you receive valid input.
Note: OP did not want a complete refactoring of his code. So this is the minimal-intervention solution.
Edit your if statements to:
if(plan=='A'){
//...
} else if(plan=='B'){
//...
} else if(plan=='C'){
//...
} else {
//handle the error here.
cout << "Wrong input" << endl;
}

C++ switch statement. Default not working

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

Display the output when type specifed word as first letter and ignore the other words after it

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

cin and switch odd behaviour

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.

switch case statement not working right?

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.