Different behaviours with getline and cin together with condition - c++

I have a continuous while loop, inside which I get user input indefinitely until the user passes no input, i.e, presses enter, or an EOF is encountered (Ctrl+D).
The first attempt, I use getline function.
while (true)
{
if (not (std::getline(std::cin, sm)) or sm.empty())
break;
}
It works fine, exits the loop on no input or EOF.
On the second attempt I use standard cin:
while (true)
{
if (not (std::cin >> sm) or sm.empty())
break;
}
In this case, it does no longer work as intended. It does not exit the loop when user presses enter, only on entering EOF it exits.
What is the difference? What am I missing here?
Any kind of help would be appreciated.

Related

Pause Function it is Looping Forever

I am trying to implement a pause function in C++, but it is looping forever.
I am using macOS but I am trying to create a pause function that will work in any system... I believe my cin >> is not capturing '\n' or '\r' from the keyboard and it is looping forever.
void Transferencia::pause() {
char enter = 0;
while(enter != '\n' && enter != '\r') {
cout << "(Press Enter to Continue...) ";
cin >> enter;
}
cin.clear();
}
I want to pause my program until user press the key "enter".
But even when I press "enter/return" it keeps looping...
At very first: enter != '\n' || enter != '\r' is a tautology: Even if enter does equal one of the characters it cannot be equal to the other one. So one of the tests must be true... You actually want to stay in the loop when enter is unequal to both values.
std::cin >> ... won't read data before you press enter, but it will discard the newlines (actually, all whitespace). So it would suffice just to read one single character right without loop (the loop again would get an endless one); solely: If the user doesn't enter anything at all before pressing 'enter' key, there's no character to read from std::cin and we'd still be waiting.
What you can do is reading entire lines:
std::string s;
std::getline(std::cin, s);
That will accept empty lines as well, so does exactly what you want (note: no loop around!).
Edit (stolen from the comments; thanks, Thomas Matthews): An even more elegant way is
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
as it won't create any additional resources that would be discarded afterwards anyway (the std::string object!).
Edit 2:
Depending on type of last input operation, there might still be a newline (or even further data) buffered, e. g. after int n; std::cin >> n;. In this case, you need to skip the input yet buffered. So you would need ignore twice.
However, if the last input operation consumed the newline already (e. g. std::getline – or if there wasn't any preceding input operation at all), then this would lead to user having to press enter twice. So you need to detect what's has been going on before.
std::cin.rdbuf().in_avail() allows you to detect how many characters are yet buffered. So you can have:
if(std::cin.rdbuf().in_avail())
{
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::cout << "press enter" << std::endl;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
On some systems (including mine), though, in_avail can return 0 even though a newline is yet buffered! std::cin.sync_with_stdio(false); can fix the issue; you should execute it before very first input operation. Hopefully, you don't use C++ (streams) and C (scanf, printf, etc) IO intermixed then...
The easiest way to do this is with getline().
cin >> ignores whitespace, newline characters included. getline() will read an entire line, newline character included. However, it does not copy the newline character to the output string. If the user simply hit the enter key and nothing else, you'd end up with an empty string.
So, to get your desired behavior, you would construct your loop like this:
string line;
while(true)
{
cout << "(Press Enter to Continue...) " << endl;
getline(cin, line);
if(line == "")
break;
}
#Aconcagua has answered your question but this is what I want to add in.
Normally, for handling some specific kind of event in computer, we usually follow event-driven paradigm or event-callback.
The idea is there is an event loop that waits for a new event coming into the system. This case, keyboard is an event, the event loop then calls event-callback. What event-callback does is it compares the value of input with some conditions then do some other tasks (it might change some state of the program or notify users).
The idea is keep CPU busy by either 2 ways.
event-driven : do other tasks while waiting for a new event
multithreading: multiple threads in the system. This approach has the disadvantage is at data-race
Have fun

How while(!(cin >> x)) works to re-prompt for input

while(!(cin >> ar[i]))
{
cin.clear(); // clears bad input
while(cin.get() != '\n')
continue;
cout << "Invalid input, please enter valid scores";
}
The above code is from a much larger file. I copied this bit of a code from one of my textbooks and I don't really feel comfortable using it as I do not understand how this works.
I am using it as a measure to handle input errors.
So ar is an empty array of integers, if I decide to enter 'k', then
!(cin >> ar[i])
is true.
From here I clear the input buffer (I think that is correct, I'd like someone to confirm or dispute this please). The terminal then prints "Invalid input..."
Now if I just press Enter nothing happens, but isn't Enter the newline char? So shouldn't the code read
while(cin.get() == '\n'
?
while(!(cin >> ar[i]))
This tries to parse a value from cin and store it in ar[i]. By default, >> skips whitespace first, then sees if the characters in cin describe a legal value for whatever the type of ar[i] is. If a legal value is found, then cin stream state remains good, and its operator bool() const will kick in given the boolean not/! operation, such that the while loop will break.
If parsing fails though, the stream state will be set to one or more of:
bad (if there's some unrecoverable stream error, like stdin supplied over a network connection that gets disconnected),
fail (if the characters just didn't form a legal value for the type), or
eof (end of file, for a "proper" shutdown/close of the input, as supplied by ^D in UNIX/Linux, ^Z in Windows, and the end of input when a program's invoked as in echo input | program).
All the above modalities are described under "State Functions" here.
If the loop is entered due to any of the error conditions above...
{
cin.clear(); // clears bad input
...this does NOT clear any input data from the stream, but does clear the bad, eof and fail state flags, after which further input attempts can be made, though a stream that was in bad or eof state is likely to immediately reenter that state when further input is attempted (but not always - some OS may allow successful input after an eof conditions for std::cin if the user types/generates an EOF code then types actual text again...
while(cin.get() != '\n')
continue;
This tries to read characters from the terminal until a newline \n is encountered. The idea's clearly to clear out the rest of the presumed unparse-able input that might have led to a fail condition earlier. Sadly, if the problem was, or becomes, a bad or eof condition then this loop will hang the program, spinning burning CPU to no avail.
cout << "Invalid input, please enter valid scores";
}
If the problem was simply a mistyped value and no bad or eof condition, then the cout will prompt for further input.
Now if I just press enter nothing happens, but isnt enter the newline char?
Whenever the outer loop is executing cin >> ar[i] it will skip whitespace, including any extra newlines you type, until it sees some input (which may need to be a full newline-terminated line to get flushed by the terminal or program feeding it to the program), or a bad or eof condition. The inner while-loop is not there to get rid of empty lines - it's trying to discard the line with presumed non-numeric text in it.
Corrected code:
while (!(std::cin >> ar[i]))
{
if (std::cin.bad() || std::cin.eof())
{
std::cerr << "Fatal error on cin while reading numbers\n";
exit(EXIT_FAILURE);
}
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Invalid input, please enter valid scores\n: ";
}
The goal of this entire code is to keep printing errors and requesting input until the user enters a valid number before continue further into the program.
The loop that the entire code is enclosed in...
while(!(cin >> ar[i]))
says to loop if the input in the cin stream is invalid. Since ar is an array of integers, the input would be invalid if it is not a number.
cin.clear(); // clears bad input
When the cin stream encounters invalid input, the program begins executing the loop and continues to this line of code. Since the stream encountered invalid input, it has a flag that says there is an error. This requires that you, as the comment puts it, "clear bad input." Basically what this does is get rid of this flag. If this is not done, the flag will remain in the stream and the program will encounter another error next time the cin stream is used, regardless of whether or not the user input is valid.
while(cin.get() != '\n')
continue;
When the program took the input from the user, it took the string, char, whatever was the invalid input, but left the '\n' in the cin stream. To prevent errors the next time the cin stream is used, the program must get rid of that '\n', along with anything else that was lefty behind. cin.get() reads only one char from the cin input stream and returns it. Since the return value of this function is not being assigned to anything, all this does is discard the char that was read. In the case that more than the '\n' was left behind in the stream, this loop checks the value of the read char before disposing of it. This way, the loop keeps executing while the char that is read is NOT '\n'. Or in other words, it loops until the char that is read IS '\n'. The only thing that continue does, is tell the program to skip the rest of the current iteration of the loop and start the next iteration. In this situation, this is equivalent to giving the loop an empty body. You could very well replace continue; with {} and the program would do the exact same thing.
cout << "Invalid input, please enter valid scores";
The program has cleared the flag in cin and has also cleared any data from cin that may have been left behind. Now that all the errors from the invalid input have been handled, there is only one more thing to do. It's time to notify he user that the input was invalid and request new input. If the user enters more invalid input, the loop repeats. If the user enters valid input, the program continues on to the next line of code.

Do stuff with cin buffer until empty

I want to have my program read through the cin buffer until there's nothing left in it to read.
What a lot of places seemed to suggest for this was:
while (cin)
{
cin >> s;
//do stuff with s
}
However, when I try this, even while the cin buffer is empty, the program just infinitely waits for input and executing the loop.
Doing while(cin >> s) does the exact same thing.
If standard input is attached to a terminal, the program will wait for input until it gets an EOF condition, which you can send on POSIX systems with a Ctrl-D
You are correct it will wait forever for a new line.
What you could do is this:
while(cin >> s){
//do stuff with s
}
What this does is while you can still read into s then do stuff. You will eventually hit the end of the buffer and it will stop.
I believe with the way you are doing it, the computer is thinking that it could still have some information come in.

getline causes infinite loop when redirecting file to standard input

The following code simply echoes the standard input to the standard output. If I run the program like so ./a.out, I can type anything and the program works fine. However, if I run it like this ./a.out < input.txt I get an infinite loop, regardless of the content of input.txt.
#include <iostream>
using namespace std;
int main() {
string input;
while (true) {
cout << "Type your input: ";
getline(cin, input);
cout << input << endl;
}
return 0;
}
What am I doing wrong?
EDIT: To clarify, I expect that after the input from the input file is finished, getline waits for more input from stdin. Instead, it continues to read when nothing is there.
You don't have a terminating condition for your loop: while (true) is an infinite loop in any case - that is, without a break/exit/etc. in the loop body.
I'm guessing that when using your program to echo stdin you end it by pressing Ctrl-C. Run your program using ./a.out, and type Ctrl-D (EOF): you'll also get an infinite loop.
Look over the docs for getline: use the return value to end your loop:
while (getline(cin, input))
Your loop has no terminating condition, be it a break, or right inside the while part. Instead, you probably want this:
while (getline(cin, input))
That will end when the input fails, most likely resulting from having reached EOF.
What you're doing wrong is that you ignore the result of an input operation, in this case getline.
You must never ignore the result of an input operation. It is always a programming error to do so. You cannot know or make assumptions about the state of external data, so you must always check whether an input operation succeeded. If it does not, then it is generally an error to access the purported input variable for reading, so you really need to check every time, and before accessing the result.
In the present case, std::getline returns a reference to the stream object, and you can evaluate the stream as a boolean. It evaluates as true if and only if the extraction succeeded; otherwise, you must not use the result (and presumably stop reading).
All in all, the code should go like this:
for (std::string line; std::getline(std::cin, line); )
{
// use "line"
}

Detecting EOF in C++ from a file redirected to STDIN

Executing the command:
./program < input.txt
with the following code checking:
string input;
while(cin) {
getline(cin, input);
}
The above code seems to generate an extra getline() call where input is empty. This happens regardless of whether or not there's a \n on the last line of input.txt.
#Jacob had the correct solution but deleted his answer for some reason. Here's what's going on in your loop:
cin is checked for any of the failure bits (BADBIT, FAILBIT)
cin reports no problem because nothing has yet been read from the file.
getline is called which detects end of file, setting the EOF bit and FAILBIT.
Loop executes again from 1, except this time it exits.
You need to do something like this instead:
std::string input;
while(std::getline(std::cin, input))
{
//Have your way with the input.
}
How about this:
string input;
while(getline(cin, input)) {
//do something with input...
}
EDIT: please note, in the example below, I show you "how to detect EOF". As #Billy has pointed out, you probably want to use good() instead of eof() to detect any error condition or eof. I had included information about this at the end of my answer, but it's important, so I'm adding this note at the top to ensure that it's clear.
(original answer follows)
You want this:
string input;
while( !cin.eof() ) {
getline(cin, input);
}
using operator! on an iostream only checks whether a failure or other error condition has occurred. ios::operator!().
You can use good() in place of !eof() to check for any of the conditions eof, badbit, or failbit. ios::good().