Here's the code :
cout << "Please enter the file path: ";
string sPath;
getline(cin, sPath);
cout << "Please enter the password: ";
string sPassword; getline(cin, sPassword);
Problem is, when I run it it displays "Please enter the file path: " then it displays "Please enter the password: " and then waits for the password. It seems to completely skip the first 'getline()'.
Later edit: Yes there are some input operations done before.
int iOption = 0;
while (iOption == 0)
{
cout << "(E/D): ";
switch (GetCH())
{
case 'E':
iOption = 1;
break;
case 'e':
iOption = 1;
break;
case 'D':
iOption = 2;
break;
case 'd':
iOption = 3;
break;
default:
break;
}
}
And the code for GetCH() in case anyone asks.
char GetCH ()
{
char c;
cin >> c;
return c;
};
It looks like the rest of the line that was input for GetCH still remains in the buffer at the time that you call getline, i.e. at least a \n and this is what you are reading in the first getline call. The program doesn't block waiting for user input because the getline request can be satisfied by the partial line still queued for reading.
Consider modifying your GetCH function to read whole lines as well.
E.g. something like (totally untested, I'm afraid):
int GetCH()
{
std::string inputline;
// Read until error or we receive a non-empty line
while( std::getline(std::cin, inputline) && inputline.empty() )
{
}
return inputline.empty() ? EOF : inputline[0];
}
You need to clear whatever available in input stream like below
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max())
I have a cin.clear() before the while loop and have modified the GetCH option to get a whole string with 'getline' and only return the first letter.
char GetCH ()
{
string c;
getline(cin, c);
return c[0];
};
It works like a charm now. Thanks to everyone for the help.
Related
My first program in C++ is a command line survival game. I have a switch statement in a while loop, but it always goes through once and runs the default choice before getting the users input. Here's the relevant code:
int menu() {
while (true) {
char choice = getChoice();
switch(choice) {
case 'p':
{
system("clear");
Arena arena(player, difficulty);
arena.play();
}
break;
case 'u':
{
system("clear");
player.save();
player.init();
}
break;
case 'd':
{
system("clear");
changeDifficulty();
}
break;
case 'q':
{
system("clear");
return 0; // return menu(); in main()
}
default:
{
system("clear");
cout << nInvalid option! Press a key to choose: p, u, s, or q\n\n";
break;
}
}
}
}
getChoice Function
char getChoice() {
cout << " Main Menu\n";
cout << "---------------------\n";
cout << "p - play game" << endl;
cout << "u - change user" << endl;
cout << "d - change difficulty" << endl;
cout << "q - quit\n" << endl;
char choice = getchar();
return choice;
}
Everything works fine after it goes through once and runs the code from the default option. Here's what I get every time the program re-enters this loop:
Invalid option! Press a key to choose: p, u, s, or q
Main Menu
---------------------
p - play game
u - change user
d - change difficulty
q - quit
Thanks for any help in advance!
Assuming you use the standard getchar function.
The problem is most likely that when you enter your "choice" you enter the 'p' (for example) and then press the Enter key. That Enter key will also be in the input as a newline '\n'. So the next time you call getChoice (and it calls getchar) you read that newline.
There are basically four ways to solve it:
The C way, using scanf instead of getchar, and ask scanf to read and discard leading whitespace (like newlines):
char choice;
scanf(" %c", &choice);
// Note space in front of the %c, which tells scanf to discard leading whitespace
Read the character, and then read and discard everything else until the newline.
Read the whole line into a string, and the parse out the character.
Use std::cin and the normal formatted input operator >>, as that will skip leading whitespace.
I really recommend the last (number 4) method.
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')
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;
}
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;
}