Checking input on a char variable - c++

I'm trying to validate input for a quit/return question in my program so the user is forced to enter either 'r' or 'q'.
I have managed to get it almost working. The problem is if the user enters 'r' or 'q' at the beginning followed by random letters then the program accepts that input. Any ideas on how to get the program to allow only a single 'r' or 'q' ?
void exit()
{
char choice;
bool badInput;
do
{
cout << "Press 'r' to return to the menu\nPress 'q' to quit the program\n\n" << endl;
cin >> choice;
badInput = cin.fail();
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
} while (badInput == true && choice == 'r' && choice == 'q' && (cin.peek() == EOF));
if (choice == 'q')
{
system("CLS");
cout << "Bye!\n";
system("PAUSE");
}
else if (choice == 'r')
{
system("CLS");
main();
}
else
{
exit();
}
}

You've got a very strange way of approaching this problem that's got a lot of issues. In particular, creating a function called exit() is problematic since that's a core function, and calling it recursively to try and get input is likewise not a good plan. You already have a loop, you just need to use it more effectively.
Likewise, main() is called automatically and you should never have reason to call it manually.
Here's a first pass rewrite:
void getInput()
{
char choice;
while (true)
{
cout << "Press 'r' to return to the menu\nPress 'q' to quit the program\n\n" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin >> choice;
switch (choice)
{
case 'q':
system("CLS");
cout << "Bye!\n";
system("PAUSE");
exit(0);
break;
case 'r':
system("CLS");
doMain();
break;
}
}
}
This obviously needs more work, but at least should theoretically function. In your original code you're demanding that the input value be simultaneously two different things which is an impossibility, that code will never work.
I'd also encourage you to stop doing things like system("CLS") and system("PAUSE") and instead do something in C++ natively. That's not portable code and it's terribly clunky as it depends on commands from 1980s DOS.

Handling the input
Most implementation use a buffered cin, so that input will only be returned once the user press enter. If this is not acceptable to you, you'll have to use OS-dependent functions.
If it's ok for you, then if you read a char, only the first one will be handed over: the remaining chars until the enter will wait for subsequent reads. Therefore, instead of reading a single char, I propose you to read a full line into a string:
void want_exit()
{
const string message="Press 'r' to return to the menu\nPress 'q' to quit the program\n";
string line;
cout << message << endl;
while (getline(cin, line) && line.length()!=1
&& tolower(line[0])!='y' && tolower(line[0])!='n')
{
cout << "Invalid input" <<endl << message <<endl;
line.resize(0);
}
Now line contains either a single valid char, or it is empty (in case of premature eof, meaning, that there was an input redirection and that there will anyway be no more input).
Processing the input
You can't call recursively main(): you should instead return from the function, and organize the calling function so to continue the process
if (line.empty() || tolower(line[0])!='y' ) {
system("CLS"); // This is non portable
cout << "Bye!\nPress enter...";
cin.getch(); // as good as system("PAUSE");
std::exit(0); // be aware of the naming issue !
}
return;
}
The calling function (main() ?) would then use it in a loop:
while (...) {
...
if (...)
want_exit();
}

Related

Detect blank input on integer type variable?

I am currently working on a text based adventure game as a project for class. I have mostly everything started and working fine. The only problem is when I ask the user which room they want to change to, if they enter a blank input, then a message should output saying "You must choose a room." For the life of me I cannot figure it out. Any help is much appreciated.
Code:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
bool game_play = true;
bool game_start = true;
int room_change;
int room_current = 0;
while (game_play == true) {
if (game_start == true) {
srand((unsigned int)time(NULL));
room_change = rand() % 2 + 1;
game_start = false;
}
else {
for (bool check = false; check == false;) { // Check if input is invalid
cin >> room_change;
if (cin.fail()) {
cout << "Choose an existing room.";
cin.clear();
cin.ignore();
}
else if (room_change == room_current) {
cout << "You're already in that room.";
}
else {
check = true;
}
}
}
switch (room_change) {
case 1:
cout << "You are in room 1.";
room_current = 1;
break;
case 2:
cout << "You are in room 2.";
room_current = 2;
break;
case 3:
game_play = false;
break;
default:
cout << "That room doesn't exist.";
}
}
return 0;
}
I just ran your code and when you hit enter, it will keep waiting until you enter a number or something invalid such as a character or a string. I did find that if you change your code from
cin >> room_change;
to
cin >> noskipws >> room_change;
when the user inputs a blank, it will cause the cin.fail() to return true and then proceed to print "Choose an existing room."
In your situation, the while loop will keep getting called until we have valid input. The "Choose an existing room" does get repeated because room_change is an integer, so when we hit enter, the '\n' will be left in the buffer. The while loop on the next iteration then reads that '\n' and executes the cin.fail() before letting you input something else. One solution I found is to use more cin.ignore() statements.
for (bool check = false; check == false;) { // Check if input is invalid
cin >> noskipws >> room_change;
if (cin.fail()) {
cout << "Choose an existing room.";
cin.clear();
cin.ignore();
} else if (room_change == room_current) {
cout << "You're already in that room.";
cin.ignore();
} else {
check = true;
cin.ignore();
}
}
The reason is because we want to get rid of that '\n' so that the cin.fail() does not execute. However, I did find that when you input a character, it will print "Choose an existing room" twice. It will print the first time because a character is not an integer, and a second time because of that '\n'.
The only problem is when I ask the user which room they want to change to, if they enter a blank input, then a message should output saying "You must choose a room."
Using std::getline and then extracting the number from the line using a std::istringstream is a better strategy for that.
std::string line;
std::cout << "Choose an existing room. ";
while ( std::getline(std::cin, line) )
{
// Try to get the room_change using istringstream.
std::istringstream str(line);
if ( str >> room_change )
{
// Successfully read the room.
break;
}
// Problem reading room_change.
// Try again.
std::cout << "Choose an existing room. ";
}
#include <iostream>
using namespace std;
int main(){
int room_change=200;
cout<<"Enter Blank";
cin>>room_change;
if(room_change==NULL){
cout<<"There is NO-THING"<<endl;
}
if(room_change!=NULL){
cout<<"There is something and that is :"<<room_change<<endl;
}
return 0;
}
But a much simpler approach to this would be to use Strings. If this is a Homework of sort and you are limited to Integer variable only. Its much more complicated if you want to detect if an Buffer is empty or not. Regardless of homework limitation, the OS layer input is String based. How can I use cin.get() to detect an empty user input?

Running a simple C++ function

I've just started learning the basics in C++ and currently am trying to make a program that does a few basic things. The problem I have is occurring in the pasted function below.
At this point it literally does nothing when it runs. All I'm trying to do it make it so the function runs over and over again forever, until the user enters the letter 'q'.
The function must keep running even if the user enters some random string, anything, 'q' is the only keystroke that should stop the loop.
I have tried toying around with 'cin.whatever" and haven't found success. If you have an answer please provide as much explanation as possible. Thank you!
void menu()
{
cin.clear();
cin.ignore();
char quit = 'w';
while (quit != 'q') // while loop to allow the user infinite tries
{
cout << "Which story would you like to play? Enter the number of the story (1, 2, or 3) or type q to quit: " << endl;
cin >> quit;
if (quit < '1' or quit > '3') // make sure the user picks a valid choice
{
cout << "Valid choice not selected." << endl;
}
if (quit == '1')
{
story1(); // run story 1
}
if (quit == '2')
{
story2(); // run story 2
}
if (quit == '3')
{
story3(); // run story 3
}
if (quit == 'q')
{
cout << "good bye" << endl;
break;
}
}
}
Try adding single quotes around your 1,2,3 like you did with the q. The cin is expecting a char to be entered so evaluate it as such. e.g: if (quit == '1')

How to skip 'enter' in cin.ignore()

I write a code to check char 'exit' in int cin. But I find that I need to set delimiters in cin.ignore such as '\n' and input it when running command and I think that is not friendly.
How can I change the code to skip the extracting step , maybe using other code instead of cin.ignore?
Sorry for everyone who try to read my English and answer as I not a native English user.
I mean cin.ignore is to extracts and discards characters until the given character is found, is it have a way to clear the cin buffer in C++ with discarding characters without extracting?
void checkcin(int &y)
{
string input = "", ans;
cin.clear();
cin.ignore(INT_MAX, '\n');
getline(cin, input);
while (input == "exit")
{
cout << "Are you sure to exit: ";
cin >> ans;
if (ans == "yes")
{
cout << "Bye." << endl;
exit(0);
}
else if (ans == "no")
{
cout << "Then welcome back!";
cout << "Input again: ";
cin >> input;
}
}
y = std::stoi(input);
}
The first parameter in the "std::cin.ignore()" that you are using just comes down to a very large number. This should be the maximum number of characters that the input buffer can hold. This number may be different on different systems or even header files for different compilers.
You need to press enter twice because there is nothing in the buffer to ignore. It is waiting for something to be entered to ignore. some people will use this to pause the program before the "return 0;".

Stuck in loop within a function (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')

How to prevent the user from entering more than one character in the below sample code?

I am facing problem in the below code. If the user enter more than one charater then my loop gets executed number of times equal to the length of the string entered by the user. My code is written in GNU c/c++ compiler.
Thanks in advance.
int continue_option()
{
char c;
loop:
fflush(stdin);
cin.ignore();
cout<<"\n\n\t\t\t\tPress (Y/y) - Continue / Press (N/n) - Exit :";
cin>>c;
if(c=='y'||c=='Y')
{
system("clear");
}
else if(c=='n'|| c=='N')
{
exit(0);
}
else
{
printf("\n\t\t\t\tInvalid Option.Try Again.....");
goto loop;
}
fflush(stdin);
}
First thing, don't use jumps. They are old style, and they make Dijkstra spin in his grave, on top of all the other bad consequences. I don't mean "vintage", I really mean old in the bad sense.
As of your question, I'd rather put the result in a std::string and only consider the first character in there:
std::string input;
std::cin >> input;
switch (input[0]) {
case 'y':
case 'Y':
//your code
break;
case 'n':
case 'N':
exit(0);
default:
std::cout << "Invalid text" << std::endl;
}
I would also refrain from using exit(), I'd rather rely on a function's return value to finally cause a return 0; in the main(), or some equivalent technique.
You can't stop the user from typing more than one character.
What you can do is ignore the rest of the line. You have already use cin.ignore() which ignores one character. You can use cin.ignore(large number) to ignore up to the large number or the end-of-line, whichever appears first.
Unlike flushing output files, fflush(stdin) doesn't really do anything.
Try using cin.get() or getch() to read just one character at a time. Also, I guess you'd be better off replacing the whole thing with a simple loop like:
char ch = '\0';
do
{
ch = getch();
}while((tolower(ch) != 'y') || (tolower(ch) != 'n'))
if(tolower(ch) == 'y')
{
//additional handling
}
else
{
exit(0);
}
Not exactly the same behavior, but should put you on track:
#include <iostream>
#include <iomanip>
bool is_valid_answer(char c)
{
switch(c)
{
case 'y':
case 'Y':
case 'n':
case 'N':
return true;
default:
return false;
}
}
bool continue_option()
{
std::cout << "Press (Y/y) to continue, (N/n) to exit: " << std::flush;
char c = '\0';
while (std::cin.get(c) && !is_valid_answer(c));
return ((c == 'y') || (c == 'Y'));
}
int main()
{
std::cout << "Continue option: " << continue_option() << std::endl;
}