While loop with getline doesn't end for user input - c++

I thought getline stops at a newline character, but the while loop does not end? it returns the correct data but it just sits in the terminal window. For example:
Enter an expression: #5+4#5+4
(blinking cursor)
(can enter data forever and press enter forever and it wont exit)
my code, (main.cpp):
int main()
{
string exp;
cout << "Enter an Infix Expression:";
while (getline(cin, exp, '#'))
{
string token = exp;
string post;
cout << token << endl;
IntoPost *infix = new IntoPost(token.length());
post = infix->inToPost(token);
cout << post << endl;
}
cin.get();
}

The Solution Using EOF
Your current program is looping endlessly because getline returns std::basic_istream, so while(getline()) will never equate to 'false'.
As #0x499602D2 has stated, your program is working as intended, but the extraction from getline can only end in two ways, as indicated by the reference here:
Extracts characters from is and stores them into str until the delimitation character delim is found (or the newline character, '\n', for when no delimiter is specified).
The extraction also stops if the end of file is reached in is or if some other error occurs during the input operation.
The first condition is difficult to pull off, as inputs on console are triggered by the \n character.
As for the second condition, as per #DavidC.Rankin:
You can also generate a manual EOF on Linux with [Ctrl+d] or windows with [Ctrl+z] (generally twice is required)
This means the solution is to use [Ctrl+d] or [Ctrl+z] to trigger the second condition to end your while loop at any time.
Alternative Using a Break Statement
One alternative way you can try to end the loop instead is breaking on input of an 'exit' string:
(1)
#include <algorithm>
//...
while (getline(cin, exp, '#'))
{
// removes meaningless endline chars from input
exp.erase(std::remove(exp.begin(), exp.end(), '\n'), exp.end());
if (exp == "exit"){
break;
}
//... Your While Block Code Here!
}
To break out of your while loop, you can simply use:
exit#
# Note, the endls from your couts in the loop will bleed into your inputs on your next while (getline(cin, exp, '#')), giving us unwanted newlines. To prevent this, we can get rid of the endlines from the inputs by using std::erase(). If you wish to keep those endlines in your input, simply set string token = exp; in front of the erase() line.

That's right, getline blocks the execution of the loop until a line separator is received and returns while that all is well, in the next step everything is repeated. If you want the loop not to be infinite - then put the Boolean variable key in the loop condition, and from the input check if the last character is an exit symbol and if so switch the variable key

Related

What exactly empty input means for cin.get()?

I think it's a simple question, but I don't understand the concept in this sample of code, mainly in the while loop:
#include <iostream>
const int ArSize = 10;
void strcount(const char * str);
int main(){
using namespace std;
char input[ArSize];
char next;
cout << "Enter text:\n";
cin.get(input, ArSize);
while(cin){
cin.get(next);
while(next != '\n')
cin.get(next)
strcount(input);
cout << "Enter next line, empty line ends the program:\n";
cin.get(input, ArSize);
}
cout << "The end\n";
return 0;
}
...
What I understand is that the while loop continues until cin returns false. It filters out the remaining input that's left in the buffer (because it wasn't the size of ArSize or under, or it was - then it will just filter out the newline character) until it meets the newline character. Then it counts string's characters (not important in this question), and then, let's say someone just presses enter. cin.get() discards newline character in input. So if someone for example enters an empty line of text in the terminal, it reads it as 'failed' input and cin returns false? Because if someone proceeds to the new line, just by pressing enter, it just leaves the newline character in the buffer, and cin.get() can't get it so it returns false. Or am I wrong?
In short - What exactly happens if you just press enter? cin.get() can't get the input because there's only newline in buffer and it counts it as failed input, so it returns false?
If cin.get(input, ArSize); reads no characters (i.e. the first character it encounters is a newline) it calls setstate(failbit) putting the stream into a failed state and therefore while(cin) becomes false, ending the loop.
As you can see here from the CPP reference https://en.cppreference.com/w/cpp/io/basic_istream/get
cin. get() is used to read the next character from the keyboard buffer and it returns that character in case it was available to be read and returns EOF otherwise and sets failbit and eofbit (which makes the expression in the if statement evaluates to false).
now let's see the code in action line by line:
while(cin){
this evaluates to true as long as the failbit flag in the cin object is set to goodbit showing no error. (https://en.cppreference.com/w/cpp/io/ios_base/iostate)
cin.get(next);
while(next != '\n')
cin.get(next)
the first line reads the next character from the keyboard buffer and stores it in the next variable and the while loop checks for the newline character which is equivalent to pressing Enter if it is not the next character in the buffer then continue reading and storing in next until it meets a newline character then it exits the loop returning to the outer while loop.
strcount(input);
cout << "Enter next line, empty line ends the program:\n";
cin.get(input, ArSize);
then strcount function as I assume is used to count the characters entered by the user in the input array by this line of code before the while loop.
cin.get(input, ArSize);
and then at the last line inside of the while loop, the program reads another input by the user.
Please Note:
the use of these three lines here is to make sure that each line is read at every single loop with no characters read in the second input before the newline character appears even if the number of characters is bigger than the ArSize variable. when that happens the first line before the while loop will read the number of ArSize from the buffer and if there are remaining characters other than the newline it will be read by the three lines until a newline appears so that the next get function will start looking for characters in the buffer after the previous newline.
cin.get(next);
while(next != '\n')
cin.get(next)
if there is anything unclear please let me know.

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

Issue When Clearing cin Buffer After Using cin.getline()

I am using getline (the cin.getline() one) to get a string from cin and finding an issue with a special case. If a user inputs more characters than the the streamsize argument (in this case, 50), the cin buffer holds them and puts them into the next cin call. If I use cin.clear() and cin.ignore() and the user enters in fewer characters than the streamsize argument, then the program waits for the user to press enter again before it continues. So I use strlen to check the size of the string and only use cin.clear() and cin.ignore() if the string has 50 characters. This chops off the extra characters that the user entered after the 49th character. The problem is that when the user enters exactly 49 characters, then there are no extra characters in the buffer to chop off with the cin.clear() and cin.ignore() calls and therefore the program will sit and wait for the user to press enter another time.
A couple of questions:
1) Is there a flag I can check to see if there are characters in the buffer so I can clear() and ignore() only when this flag is true?
2) Is there any other way I can call this same getline function that cuts off all characters after the streamsize argument?
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
#define SIZE 50
void getString(char*);
int main() {
char words[SIZE];
getString(words);
return 0;
}
void getString(char* words) {
cout << "Enter your string: ";
cin.getline(words, SIZE);
if (strlen(words) == SIZE - 1) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
A sample 49 character input that would cause the issue:
abcdefghijklmnopqrstuvwxysabcdefghijklmnopqrstuvw
Erase or add one letter to see the program's normal performance.
You can use istream::gcount() to decide whether there are any more characters other than '\n' left in the line still.
Here are the cases you need to think about.
The return value of cin.gcount() is less than SIZE-1. In this case, there is nothing left in the line. You don't have to worry about ignoring the rest of the line.
The return value of cin.gcount() is SIZE-1. This could be due to two scenarios.
The user enters SIZE-2 characters followed by a newline. In this case, there is nothing left in the line. You don't have to worry about ignoring the rest of the line.
The user enters SIZE or more number of characters followed by a newline. In this case, there are still some characters left in the line. You will want to ignore the rest of the line.
The return value of cin.gcount() is SIZE. This can happens only when the user enteres SIZE-1 characters followed by a newline. All the characters from the line are read into the argument provided to the function. The newline character is read and discarded. You don't have to worry about ignoring the rest of the line.
Give the above cases, the only time you have to worry about ignoring the rest of the line is when you run into case 2.2. That condition is met when cin.gcount() == SIZE-1 and strlen(words) == SIZE-1.
void getString(char* words) {
cout << "Enter your string: ";
cin.getline(words, SIZE);
if (cin.gcount() == SIZE-1 && strlen(words) == SIZE-1)
{
// There are characters in the stream before the \n.
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}

functionality of cin in c++

I'm a bit confused by the results of the following function:
int main() {
string command;
while(1) {
cin >> command;
if(command == "end")
return 0;
else
cout << "Could you repeat the command?" << endl;
}
return 0;
}
First of all - the output line ("could you...") repeats once for each individual word in the input (stored in command). So far as I can see, it should only be possible for it to happen once for each instance of the loop.
Also, when the line 'if(command == "end")' is changed to 'if(command == "that's all")' it never triggers. A little testing suggested that all of the whitespace was removed from the command.
Could someone explain to me what's going on here?
Thanks
The formatted input operator >>() reads space separated tokens from input. If you want to read whole lines, use the getline() function:
string command;
getline( cin, command );
Most (possibly all) operating systems buffer input. When you type a string of words and then hit [enter] it is only at the time you hit enter that the input is usually passed to your program. Thus that is when it will start reading the input and separating it out into individual words (because as Neil mentions, the >> reads words, not lines). Thus your program goes through the loop multiple times (once per word you had in the line) even though you only hit enter once.
So, you are correct when you think it should only display "could you..." once per loop. That is what is happening.
Likewise, you'll never have a command that contains more than one word because of the space delimiter. As mentioned, use getline() to retrieve the entire text for the line you entered.

Using cin.get() to grab a line of text, then using it in a loop to display that line?

Ok, so I came across this code snippet in my textbook that's supposed to echo every other character a user types in. Now, I understand the every other character part, but I'm having difficulty with the use of cin.get(). I understand why the first cin.get() is there, but why is it also inside the loop? I'm guessing I'm not fully grasping the nature of input streams...
EDIT: It just clicked... I'm an idiot. Thanks for clearing that up.
char next;
int count = 0;
cout << "Enter a line of input:\n";
cin.get(next);
while (next != '\n')
{
if ((count%2) == 0)
cout << next;
count++;
cin.get(next);
}
Thanks in advance!
cin.get in this case does not "grab a line of text" as you seem to believe. cin.get in this case grabs just a single character. With cin.get you read characters the user is typing in, one by one, one after another. This is why you have cin.get in a loop.
The call to cin.get(next) that comes before the loop is only placing the first character of buffered user input into the variable 'next.'
Once inside the loop, and the character stored in 'next' has been processed (echoed if at an even index, otherwise ignored), cin.get(next) needs to be called again to retrieve the next character.
Its printing characters present at even positions
char next;
int count = 0;
cout << "Enter a line of input:\n";
cin.get(next);//gets first character (position zero) from input stream
while (next != '\n')//check whether the character is not line feed(End of the line)
{
if ((count%2) == 0)//checks if position is even
cout << next; //if yes print that letter
count++; //increments the count
cin.get(next); //gets next character from input stream
}
We require two cin.get(...)
before entering the while loop we need to know first character(position zero)
inside while loop for getting next character
but what is the use of outside cin.get(ch) what does it do
how cin.get() works inside loop
both behaviours are lookin different
so it's making confusing
there is a statement in loop to print the character got using cin.get(next) but it will not print it.... it will print all together after pressing enter key ... actually it should display the characters as we type from the keyboard but it is not actually working like that
istream& get(char &c) gets a character from the input stream.
so on the first call cin.get(next) you typed:
"hello world!"
Then future cin.get(next) will fetch h, e, l, l, etc... on every call until the there are no more characters in the input stream and that's when it will block asking the user for more input.
Streams in C++ , are buffered. Think of them as a line of letters. When you call cin.get(var) the first character in that line is removed and returned to you. So, that's how it works.
An example would help better. When the first cin.get() is executed, let's say you type in :
LISP
and then, cin.get() will return (in the var.) L and then the buffer will look like ISP... the next call will place I in the var. and the buffer will look like SP and so on...