cin.get() is taking input from previous cin.get() - c++

I'm super new to this, and am trying to code a simple shop interface for a CLI adventure game.
The problem I'm having is in between uses of cin.get(). I've read another post but don't understand what's being said. Can someone explain like I'm 5?
I use cin.get() once in the MainMenu() to wait for Enter to continue. This punishes the player's health if they do anything other than press Enter.
I then move forwards to the Introduction(), where I'm trying to pull the same trick, but it carries the input from cin.get() from the MainMenu() function.
The other code in main() is just keeping track of the character's health and stopping the program if it reaches 0 by way of another function.
#include <iostream>
#include <ctime>
#include <string>
using namespace std;
int MainMenu()
{
cout << "\nPress the ENTER key\n";
char Input = cin.get();
if (Input == '\n')
{
return 0;
}
else if (Input != '\n')
{
cout << "I meant ONLY the ENTER key... Oh well its your health pool.\n";
CharHealth(-2);
cout << "You took 2 damage. \nYou now have " << CharHealth(0) << "Health.\n";
return 0;
}
}
int Introduction()
{
cout << "you awake in a puddle, walk to town. \nPress [ENTER]";
char Input = cin.get();
if (Input != '\n')
{
cout << "\nfor real?\nTake Another 2 Damage\nwhat did you think?... Idiot" ;
CharHealth(-2);
return 0;
}
else
{
return 0;
}
}
int main()
{
MainMenu();
Introduction();
while (CharHealth(0) > 0)
{
cout << "winner";
return 0;
}
cout << "\n You died. idiot.";
return 0;
}
Don't judge my story telling, everything is still placeholders right now.
My console just reads:
Press the ENTER key
asdf
I meant ONLY the ENTER key... Oh well its your health pool.
You took 2 damage.
You now have 1Health.
you awake in a puddle, walk to town.
Press [ENTER]
for real?
Take Another 2 Damage
what did you think?... Idiot
You died. idiot.
C:\Users\KR's\Documents\text Shop>

cin.get() reads 1 char at a time. So, for example, if the user types in asdf, then the next cin.get() will read and return a, leaving sdf in cin's input buffer. Then the next cin.get() will read and return s, leaving df in cin's input buffer. And so on. Your code is not taking that into account. There is only 1 input buffer in cin, there is no per-function input buffer, like you are expecting.
If the user does not type in what you want, use cin.ignore() to discard the unwanted input. For example:
...
#include <limits>
...
int MainMenu()
{
cout << "\nPress the ENTER key\n";
char Input = cin.get();
if (Input != '\n')
{
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // <-- ADD THIS
cout << "I meant ONLY the ENTER key... Oh well its your health pool.\n";
CharHealth(-2);
cout << "You took 2 damage. \nYou now have " << CharHealth(0) << "Health.\n";
}
return 0;
}
int Introduction()
{
cout << "you awake in a puddle, walk to town. \nPress [ENTER]";
char Input = cin.get();
if (Input != '\n')
{
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // <-- ADD THIS
cout << "\nfor real?\nTake Another 2 Damage\nwhat did you think?... Idiot" ;
CharHealth(-2);
}
return 0;
}

cin.get() reads only one character and leave other inputted things on the stream.
It seems you want to read until \n is read. It can be done like this:
int MainMenu()
{
cout << "\nPress the ENTER key\n";
int count = 0;
while (cin.get() != '\n') count++;
if (count == 0)
{
return 0;
}
else if (count != 0) // we won't need this if statement, but I respect you
{
cout << "I meant ONLY the ENTER key... Oh well its your health pool.\n";
CharHealth(-2);
cout << "You took 2 damage. \nYou now have " << CharHealth(0) << "Health.\n";
return 0;
}
}
(warning: This code will fail into an infinite loop if we get EOF before newline)

Related

C++ program stuck in an infinite loop

Please note that I am a complete beginner at C++. I'm trying to write a simple program for an ATM and I have to account for all errors. User may use only integers for input so I need to check if input value is indeed an integer, and my program (this one is shortened) works for the most part.
The problem arises when I try to input a string value instead of an integer while choosing an operation. It works with invalid value integers, but with strings it creates an infinite loop until it eventually stops (unless I add system("cls"), then it doesn't even stop), when it should output the same result as it does for invalid integers:
Invalid choice of operation.
Please select an operation:
1 - Balance inquiry
7 - Return card
Enter your choice and press return:
Here is my code:
#include <iostream>
#include <string>
using namespace std;
bool isNumber(string s) //function to determine if input value is int
{
for (int i = 0; i < s.length(); i++)
if (isdigit(s[i]) == false)
return false;
return true;
}
int ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
else if (rtrn == "2" and isNumber(rtrn)) { return true; }
else {cout << "Invalid choice." << endl; ReturnCard(); };
return 0;
}
int menu() //function for operation choice and execution
{
int choice;
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == 1 and isNumber(to_string(choice))) { cout << "Your balance is $" << balance; "\n\n"; }
else if (choice == 7 and isNumber(to_string(choice))) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; menu(); }
} while (ReturnCard()==false);
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}
I've tried every possible solution I know, but nothing seems to work.
***There is a different bug, which is that when I get to the "Do you wish to continue?" part and input any invalid value and follow it up with 2 (which is supposed to end the program) after it asks again, it outputs the result for 1 (continue running - menu etc.). I have already emailed my teacher about this and this is not my main question, but I would appreciate any help.
Thank you!
There are a few things mixed up in your code. Always try to compile your code with maximum warnings turned on, e.g., for GCC add at least the -Wall flag.
Then your compiler would warn you of some of the mistakes you made.
First, it seems like you are confusing string choice and int choice. Two different variables in different scopes. The string one is unused and completely redundant. You can delete it and nothing will change.
In menu, you say cin >> choice;, where choice is of type int. The stream operator >> works like this: It will try to read as many characters as it can, such that the characters match the requested type. So this will only read ints.
Then you convert your valid int into a string and call isNumber() - which will alway return true.
So if you wish to read any line of text and handle it, you can use getline():
string inp;
std::getline(std::cin, inp);
if (!isNumber(inp)) {
std::cout << "ERROR\n";
return 1;
}
int choice = std::stoi(inp); // May throw an exception if invalid range
See stoi
Your isNumber() implementation could look like this:
#include <algorithm>
bool is_number(const string &inp) {
return std::all_of(inp.cbegin(), inp.cend(),
[](unsigned char c){ return std::isdigit(c); });
}
If you are into that functional style, like I am ;)
EDIT:
Btw., another bug which the compiler warns about: cout << "Your balance is $" << balance; "\n\n"; - the newlines are separated by ;, so it's a new statement and this does nothing. You probably wanted the << operator instead.
Recursive call bug:
In { cout << "Invalid choice of operation."; menu(); } and same for ReturnCard(), the function calls itself (recursion).
This is not at all what you want! This will start the function over, but once that call has ended, you continue where that call happened.
What you want in menu() is to start the loop over. You can do that with the continue keyword.
You want the same for ReturnCard(). But you need a loop there.
And now, that I read that code, you don't even need to convert the input to an integer. All you do is compare it. So you can simply do:
string inp;
std::getline(std::cin, inp);
if (inp == "1" || inp == "2") {
// good
} else {
// Invalid
}
Unless that is part of your task.
It is always good to save console input in a string variable instead of another
type, e.g. int or double. This avoids trouble with input errors, e.g. if
characters instead of numbers are given by the program user. Afterwards the
string variable could by analyzed for further actions.
Therefore I changed the type of choice from int to string and adopted the
downstream code to it.
Please try the following program and consider my adaptations which are
written as comments starting with tag //CKE:. Thanks.
#include <iostream>
#include <string>
using namespace std;
bool isNumber(const string& s) //function to determine if input value is int
{
for (size_t i = 0; i < s.length(); i++) //CKE: keep same variable type, e.g. unsigned
if (isdigit(s[i]) == false)
return false;
return true;
}
bool ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
if (rtrn == "2" and isNumber(rtrn)) { return true; } //CKE: remove redundant else
cout << "Invalid choice." << endl; ReturnCard(); //CKE: remove redundant else + semicolon
return false;
}
int menu() //function for operation choice and execution
{
string choice; //CKE: change variable type here from int to string
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == "1" and isNumber(choice)) { cout << "Your balance is $" << balance << "\n\n"; } //CKE: semicolon replaced by output stream operator
else if (choice == "7" and isNumber(choice)) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; } //CKE: remove recursion here as it isn't required
} while (!ReturnCard()); //CKE: negate result of ReturnCard function
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}

_getch() not detecting keystrokes first few times

I'm writing my first actual program in C++, and I'm just wondering why _getch() takes a few times to actually detect that I pressed a key. It'll usually take 2 or 3 tries before it actually picks it up and does what it's supposed to, and the first few times it just acts like nothing's happened. Here's all the relevant code:
#include <iostream>
#include <conio.h>
int main()
{
using namespace std; // so i don't have to do 'std::cout' for every time I want to print, among other things
cout << "Bag's Example Program\n\n";
system("pause"); // waits for user input, with a "Press any key to continue" message
bool chosen = false;
while (chosen == false) {
system("cls"); // clears the screen
cout << "Enter a string: ";
string words;
cin >> words;
cout << "You entered: " << words << "\n\nIs this correct? (Y/[N]): ";
_getch(); // waits for user input
if ((_getch() != 121) || (_getch() != 89)) { // if user's keystroke was NOT the 'y' key
cout << "user selection was NO\n";
}
else { chosen = true; }
}
}

C++ want to return to where left off

#include <iostream>
#include <time.h>
#include <stdlib.h>
using namespace std;
int main()
{
int password;
system("cls");
cout <<"Login"<< endl;
cout <<"Enter password to continue"<< endl;
cin >> password;
cin.ignore().get();
if( password == 1111)
{
system("cls");
cout <<"Access Granted"<< endl;
system("PAUSE");
system("cls");
return main();
}
//Want to make if( password == 1111) return to main(), but start where it left off
//I want it to start at cout <<"Files:'<< endl;
cout <<"Files:"<< endl;
cout <<"\n E \n N \n G \n S \n"<< endl;
cout <<"Choose a file"<< endl;
string file;
cin >> file;
cin.ignore().get();
if(file == "E" || file == "e")
{
system("cls");
cout <<"E:"<< endl;
cout <<"Age:"<< endl;
cout <<"Grade:"<< endl;
cout <<"Eye color:"<< endl;
cout <<"Hair color:"<< endl;
system("Pause");
}
else if(file == "N" || file == "n")
{
system("cls");
cout <<"N:"<< endl;
cout <<"Age:"<< endl;
cout <<"Grade:"<< endl;
cout <<"Eye color:"<< endl;
cout <<"Hair color:"<< endl;
system("Pause");
}
else if(file == "G" || file == "g")
{
system("cls");
cout <<"G:"<< endl;
cout <<"Age:"<< endl;
cout <<"Eye color:"<< endl;
cout <<"Hair color:"<< endl;
system("Pause");
}
else if(file == "S" || file == "s")
{
system("cls");
cout <<"S:"<< endl;
cout <<"Age:"<< endl;
cout <<"Eye color:"<< endl;
cout <<"Hair color:"<< endl;
system("Pause");
}
else
{
system("cls");
cout<<"Access Denied!"<< endl;
system("PAUSE");
return 0;
}
return 0;
}
Having trouble figuring out how to continue where the main function left of. I have been teaching myself how to code so I don't know if that's even possible. Read the comment I left In the code to better understand what I am speaking of. Thx
If you remove this line:
return main();
then the computer will continue executing the instructions in the order they are written - in particular, the next one will be cout <<"Files:"<< endl;.
To control the flow of your program, you have multiple options.
If you're doing things multiple times, you have for and while loops. If you want to stop a loop and get out, use break. If you want to skip to the next iteration, use continue.
If you want to simply jump to a different place in the program, you can use goto but it's a code smell. It's generally better to avoid it as it tends to compromise readability.
If you want to do a task that can he interrupted, you can use a void function. If you want the function to stop what it's doing and continue main, use return.
However, in your particular example, it seems like you don't quite understand how an if statement works.
If the ifs condition is true, it executes whatever is in the curly braces ({ ... }). It continues execution right after the closing brace automatically. You don't need to return to main explicitly.
What you actually did there (by mistake) is write a recursive function (one that calls itself until a condition is met).
You seem to have significantly misunderstood program flow in a C++ program. return main() will make a fresh call into main, so the user will see the "login" prompt again. When that call to main has ended, because you used the keyword return, it will exit the previous call to main. Neither of these is what you want. It's also explicitly forbidden by the C++ standard to call main from another function.
I also note that after the long block of indented functionality, you have an else statement that looks like it is the else to if (password == 1111).
Indentation means nothing to the C++ compiler, it's purely for human readability.
I think what you are trying to achieve is something more like this:
if (password == 1111)
{
std::cout << "Access granted\n";
}
else
{
std::cout << "Access denied\n";
return 0;
}
std::cout << "Files:\n";
Here, if the user types 1111, then the first compound block of code is executed, and execution resumes after the end of the if/else block, i.e. the next instruction is to print Files.
If the user types something else, the else block is executed. It finishes with return 0 which exits the function and returns the value of 0 to the caller.
#include <iostream>
#include <string>
int main()
{
std::cout << "Login:\n";
std::string password;
std::getline(std::cin, password);
if (password == "1111")
std::cout << "That's correct.\n";
else {
std::cout << "Access denied.\n";
return 0;
}
std::cout << "Files:\n";
// your code here
}
Demo: http://ideone.com/DSYAG4

C++ input not being read

I just started with c++ (coming from java) and I'm trying to do some basic exercises. The idea is to ask for any input other than 5, if the user inputs 5, display a message, and if the user inputs anything other than 5 ten times, display another message. Here's the code:
void notFive () {
int count = 0;
while (count < 10) {
int input = 0;
cout << "Enter any number other than 5." << endl;
cin >> input;
if (input == 5)
break;
count++;
}
if (count == 10)
cout<<"You are more patient than I am, you win.";
else
cout << "You weren't supposed to enter 5!";
}
}
My problem is that all this code does is print out "Enter any number other than 5." 10 times, then say "You are more patient that I am, you win." any ideas what is wrong?
if you guys want all my code (to make sure I'm not just being an idiot) here it is:
#include <iostream>
#include <stdio.h>
using namespace std;
class Hello {
public:
void notFive () {
int count = 0;
while (count < 10) {
int input = 0;
cout << "Enter any number other than 5." << endl;
if ( ! (cin >> input) ) {
cout << "std::cin is in a bad state! Aborting!" << endl;
return;
}
if (input == 5)
break;
count++;
}
if (count == 10)
cout<<"You are more patient than I am, you win.";
else
cout << "You weren't supposed to enter 5!";
}
}hello;
int main() {
Hello h;
h.notFive();
return 0;
}
Your code works perfectly for me (in Visual Studio 2012) when I change notFive to main. Your problem must lie outside this code (possibly because cin is in a broken state, as others have suggested).
Change this line:
cin >> input
To this:
if ( ! (cin >> input) ) {
cout << "std::cin is in a bad state! Aborting!" << endl;
return;
}
The behavior you describe is what would happen if Something Bad happened to cin before this code was run.
Edit:
Add this same code to earlier uses of cin to find out where it's entering a bad state.
An example of this happening would be if the code tried to read an int, and the user typed a letter of the alphabet.
You can also call cin.clear(); to restore the working state of cin.
Here are my comments:
fflush(stdin) is not valid. The stdin cannot be flushed. Also,
this may not be the same input as cin.
You need to check for cin.fail after cin >> input. If I enter a
letter, your input statement will fail.

How to translate cout/cins to printf/scanfs?

I coded an easy game. I know how to use cout/cin but having problems with printf/scanf. The code below works well with cout/cin. Question is, how to convert them into printf/scanf? Why the codes in comment don't work?
Edit: I mean if I delete cout/cin lines and when I use printf/scanf instead it doesn't work properly.
#include <iostream>
#include <time.h>
using namespace std;
int main()
{
srand(time(NULL));
int min=0, max=1000, guess, counter=0;
bool winner=false;
char answer;
while(counter<10){
guess = rand()%(max-min)+min;
// printf("Did you pick %d? \t", guess);
// scanf("%c", &answer);
cout << "Did you pick " << guess << "?\t";
cin >> answer;
if(answer=='y'){ // yes
winner=true;
// printf("Computer wins.\n");
// printf("You picked: %d", guess);
cout << "Computer wins." << endl;
cout << "You picked: " << guess;
break;
}
else if(answer=='m'){ // more
min=guess;
counter++;
}
else if(answer=='l'){ // less
max=guess;
counter++;
}
}
if(winner==false){
// printf("User wins.\n");
cout << "User wins." << endl;
}
return 0;
}
The problem is that scanf() doesn't remove the newline '\n' character from stdin, so on the next iteration the next scanf() reads it and tries to process it, seeming to ignore the input.
Try this instead:
scanf("\n%c", &answer);
That way, you expect the newline and scanf() consumes it.