Using cin.get() in a tight loop - c++

I'm not new to programming, but I am relatively new to C++. I would like to distribute simple console applications so I can help others as I learn. The vast majority of machines on the campus of my university are windows based, and have the Borland compiler installed by default. I prefer to do my development on a Linux-based system with g++ and other tools. So I'd like to add some cross-platform way of leaving the program running until the user presses enter. That way, the user is able to view the output even if he or she double clicked on the exe rather than running it in the console in windows. To do this, I wrote something similar to:
#include <iostream>
using namespace std;
int main()
{
float val1, val2;
bool wait = true;
cout << "Please enter the first value to add: ";
cin >> val1;
cout << "Please enter the second value to add: ";
cin >> val2;
cout << "Result: " << val1 + val2 << endl << endl;
cout << "Press enter to exit...";
while (wait)
{
if (cin.get() == '\n')
wait = false;
}
return 0;
}
Using the code above, the program exits after displaying the result. However, if you comment out the cin calls, it works as expected. This leads me to believe that cin.getline is picking up my enter key press from my last data entry. I suspect this is due to the tightness of the loop. I have learned that there is no cross-platform sleep function in C++, so that is not an option. What else can I do to make this work?

You can add
cin.ignore(1);
or
cin.ignore(INT_MAX, '\n');
before you call cin.get(). This will ignore the newline left from the user entering the second number or all the characters in the buffer until a newline.
Also you neither need to compare the return value of get to '\n' nor put it in a loop. The user has to hit enter for get to return, so
cout << "Press enter to exit...";
cin.ignore(INT_MAX, '\n');
cin.get();
Is sufficient.
What happens if you do
cout << "Press enter to exit...";
while (wait)
{
if (cin.get() == '\n')
wait = false;
}
Is that the loop is entered, and cin.get() is called. The user can enter any amount of text at the console as he wants. Say they entered
Hello
in the console. Then the user presses the Enter key. cin.get() returns H, and ello\n is still left in the buffer. You compare H with \n and see that they are not equal, continue the loop. cin.get() is called and since there is already text in the buffer, returns e immediately. This loop continues wasting time until it gets to the last character of the buffer which is \n and it compares true with \n so the loop breaks. As you can see, this is a waste of time.
If you do put cin.get() in a loop and compare the return value of it with \n, there is also the danger of cin coming to an end-of-file before an \n is encountered. I believe the effect of this on your program would be an infinite loop, but I'm not sure since I can't try it on Windows.
Also, even though you don't need to use a loop in the first place, you are wasting even more time with a bool because you could reduce the loop to
while (true)
if (cin.get() == '\n') break;

After cin >> you should ignore all the characters in the buffer until the `\n' with
#include <limits> // for std::numeric_limits as indicated by Marlon
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
Then you can wait for the next line with:
cout << "Press enter to exit...";
cin.get();

Related

C++ cin.ignore() skip loop

I created a for loop in my program that makes it so you have to press enter to continue. I did this Using cin.ignore().
This is the basic idea of the code that I am using.
for (int i = 0; i < 5; i++) { // loop will do it for each player data
cout << "Press Enter to Continue ";
cin.ignore();
system("cls");
cout << "Playes Data" << endl;
}
This code works fine until the player decides to input something rather than just press enter.
From what I understand, because the player inputted something, this means that there will be a buffer. You can get rid of the buffer from just using cin.ignore. This makes it so it skips an iteration and the player doesn't have to press enter to continue. I have just included a second cin.ignore, but I don't want them to have to press enter twice. Is there some way to use the second cin.ignore only if there is a buffer, or is there some other way to deal with this?
There is always a buffer. Calling std::cin.ignore() by itself, with no parameter values, simply skips the next char in the buffer, which may or may not be a '\n' char from an ENTER press.
To skip everything in the buffer, up to the next ENTER press, use std::cin.ignore(std::numeric_limits<streamsize>::max(), '\n').
You can replace
cin.ignore();
with
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Where the second option will ignore all characters including the newline the enter key puts into the stream.

If you enter the desired input twice, it outputs twice?

Heres my example:
while (response == 'y')
{
playOneGame();
cout << "Great! Do you want to play again (y/n)? ";
cin >> response;
}
And if you type in: yy
It prints the output twice:
"Great! Do you want to play again (y/n)? Great! Do you want to play again (y/n)? "
I would just like to understand why. This program is written in C++ if that matters. Thanks.
Since you are comparing it to a char (result == 'y'), I'm assuming result is also a char.
The cin operation is going just read one char, and leave the second one on the input buffer. Then, the next time through the loop, it reads the second 'y' without any additional user input required.
If you want to be sure there is nothing left in the buffer, read until you get a line terminator. Or you can read into a string:
string response = "y";
// continues on anything that starts with lowercase 'y'.
// exits on anything else.
while (response.length() >= 1 && response[0] == 'y') // length check maybe unnecessary?
{
playOneGame();
cout << "Great! Do you want to play again (y/n)? ";
cin >> response;
}
It is not clear the type of response, but I assume it is char.
char response;
while(response=='y'){
playOneGame();
cout << "Great! Do you want to play again (y/n)? ";
cin >> response;
}
cin reads all the chars until you stop sending chars to it. Simply, cin gets whole terminal line so when you press 'yy', while loop runs twice.
If loop runs twice and prints the message two times:
1. It doesn't start game again.
2. Even, it starts the game, when it is over, for the second y, it does starts game again without asking.
Modify your code to read one char and continue. You can use getche() to get one char and continue.
This is exactly what you need. Apply the code below to your real case.
#include<iostream>
#include<limits>
using namespace std;
int main()
{
char response = 0;
while(cin >> response){
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "You enterd: " << response << endl;
}
return 0;
}
Here is the explanation:
Why would we call cin.clear() and cin.ignore() after reading input?

C++ if condition not checked after goto

I'm working on a simplish game (this isn't the whole code, just the bit that I'm having issues with) and I've run into this issue; After the condition is furfilled, it goes back to the start and it offers me to reenter the string, however, whatever I enter, I just get 'Not Valid'. Does anyone know why? I'm using the GNU C++ Compiler.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string command;
mainscreen:
cout << "blab";
getlinething:
cin.ignore();
getline(cin, command);
if (command == "task")
{
goto mainscreen;
}
else
{
cout << "Not valid.";
goto getlinething;
}
return 0;
}
When I run your code with a debug print it shows that each time you read a new command you are loosing the first char of the string. In fact, when I remove your cin.ignore() it works fine.
Also, have a look at this while to see if it fits your needs:
cout << "blab";
while(1){
getline(cin, command);
if(command == "task"){
cout << "blab";
getline(cin, command);
}
else{
cout << "Not valid.";
}
}
For debugging purpose at least, why not do
cout << "'" << command << "' Not valid" << endl ;
Alright, I tested it out. Without cin.ignore(), I cannot enter the data into the string at all.
The first time I enter it captures everything. So if I wrote task, the string would say 'task', however the second time I entered it, it would say 'ask'. I don't really know why it's doing that.
The cin.ignore() line will always discard one character by default (unless it encounters EOF, which would be a fairly deliberate act on cin).
So, let's say the user enters task and then hits the enter key. The cin.ignore() will discard the 't', and the command string will contain "ask". If you want to get a match, the first time through, the user will need to enter ttask. The newline will be discarded, in either case. The same will happen until a match is encountered.

cin.get(); doesn't work when I put it in a if statement

I used cin.get() to get the program to pause and wait for user input, and it works fine. The moment I put it in an if statement, it just skips that "wait" period and continues on with the code? How can I solve this. Here is the section that is not working.
do
{
cout << "\n\n\nEnter the number of one of the following and I will explain!\n";
cout << "1.integer 2.boolian 3.floats 4.doubles 5.character";
cout << "\n\n[when you are done type 'done' to continue]\n\n";
cin >> option;
if (option = 1);
{
cout << "\nInteger is the variable abbreviated as 'int' this allows C++ to only";
cout << "\nreadwhole and real numbers \n\n";
cin.get(); //this is the part where it just skips.. it should wait
}
} while (var = 1);
The problem is that cin >> option will extract whatever integer is in the input stream but will leave the following newline character (which is there from hitting enter after typing in the value). When you do cin.get() it is simply extracting that newline character which is already there. Like so many other questions like this, the solution is to empty the input stream after you've extracted into option:
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
You are also using assignment (=) where you should be comparing for equality (==).

cin condition checking error

I am a beginner programmer learning c++. I am having a nagging issue with the cin command.
In the program section below, if I enter a wrong type at the 1st cin command, the program will not execute any of the following cin commands at all, but will execute the rest of the program.
//start
#include <iostream>
using namespace std;
int main()
{
int x=0;
cout << endl << "Enter an integer" << endl;
//enter integer here. If wrong type is entered, goes to else
if (cin >> x){
cout << "The value is " << x << endl;
}
else {
cout << "You made a mistake" << endl; //executes
cin.ignore();
cin.clear();
}
cout << "Check 1" << endl; //executes
cin >> x; //skips
cout << "Check 2" << endl; //executes
cin >> x; //skips
return 0;
}
//end
Instead of the if else, if i put the same concept in a loop
while (!(cin >> x))
the program goes into an infinite loop upon enterring a wrong input.
Please help me explain this phenomenon, as the text book i am following says the code typed above should work as intended.
Thank you
cin is an input stream. If an error occurs cin goes into a let's call it "error occured" state. While in this state no character input can be made, your request to collect a character from the input stream will be ignored. With clear() you clear the error and the input stream stops ignoring you.
Here is the ignore function prototype
istream& ignore ( streamsize n = 1, int delim = EOF );
This function gets characters from the input stream and discards them, but you can't get any character if your stream is ignoring you, so you have to first clear() the stream then ignore() it.
Also, a note on the side: If someone inputs, for example "abc", on the first input request your cin gets only one character that is 'a' and "bc" stays in the buffer waiting to be picked up, but the next call to cin gets the 'b' and 'c' stays in the buffer, so you again end up with an error.
The problem with this example is that the cin.ignore() if no arguments are handed to it only ignores 1 character after you clear(). and the second cin gets 'c' so you still have a problem.
A general solution to this problem would be to call
cin.ignore(10000, '\n');
The first number just has to be some huge number that you don't expect someone would enter, I usually put in 10000.
This call makes sure that you pick up all the characters from the false input or that you pick up every character before the enter was pressed so your input stream doesn't get into the "error occurred" state twice.
You may also want to try
if ( std::cin.fail() )
as a backup to prevent a crash due to input of the wrong type when prompted