Get the same input with EOF terminator as with .empty() function - c++

I want to get user input, and the number of characters that are given is important. I get a satisfying result with input.empty() but it terminates after I press Enter. I want it to terminate after i specifically type Ctrl+D.
1) do{ 2) while(std::getline(std::cin, input)){
getline(std::cin, input); buffer += input;
buffer += input; buffer += '\n';
buffer += '\n'; }
}while(!input.empty()); std::cin.ignore();
Other than the Enter terminator the first code work as I want it to, and the second one has a character more, which I'm not sure what it exactly is, but it does end when I type Ctrl+D. input and buffer are both std::string. So how can I get the same result as input.empty().
Thank you in advance.

In your question, you claim that the second code snippet produces one character more in buffer than the first code snippet. However, I assume that this statement is false. It is the first one which should have one character more, for the following reason:
When std::getline encounters end-of-file after reading at least one character, then both code snippets will behave the same way.
However, if std::getline encounters end-of-file before reading at least one character (i.e. if it is encountered at the start of the line), then the behavior of the two code snippets is different: The first code snippet will write an additional newline character to buffer, before the loop gets terminated, whereas the second code snippet will terminate immediately.
In other words, the first code snippet produces one character too much, because its logic is wrong. Therefore, I suggest that you use the second snippet. However, it is unclear what std::cin.ignore(); in the second code snippet is supposed to accomplish, because the function std::getline has already removed the newline character from the input stream (if it existed). Also, calling std::ignore when the end of the stream has already been reached will probably have no effect. Therefore, you should probably remove that line.

Related

Why does ignore() before getline() take one less character input?

I am using the getline() function in C++, but there is a problem that the input starts from the second character. I used the ignore() function to erase what remains in the buffer first, emptying the buffer and receiving input. How can I empty the buffer and receive input properly?
Above is the execution result. I previously used the ignore() function and the getline() function to empty the buffer and receive input because there may be some leftovers in the buffer before.
In other programs that write like that, it also receives integer input before.
void InputValue(string *st) {
//cin.clear();
cin.ignore();
getline(cin, *st);
}
int main(void) {
string str;
InputValue(&str);
cout << str;
return 0;
}
In the beginning, immediately after input, stdin (your input buffer) contains :
abcd
Those character are waiting to be extracted in whatever manner you choose. Since you are reading from stdin (using std::cin) using getline() from the stream into a std::string, getline() will consume all characters in the line, reading and discarding the trailing '\n' with all characters stored in your std::string. There are no characters left in stdin that need to be extracted using std::cin.ignore()
When you call std::cin.ignore() before getline() you are reading (and discarding) the first character waiting to be read in stdin. With the example characters above, after calling std::cin.ignore(), and extracting and discarding the character, the following is left in stdin:
bcd
So now when you do call getline (std::cin, *st); "bcd" are the only characters that are available. That is the reason why you miss the first character.
While you can std::cin.ignore() one character, the .ignore() member function is usually used to read/discard all remaining characters in a line using the form
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Where #include <limits> provides the constants representing the maximum number of the type specified, above <std::streamsize>::max() (e.g. the maximum value that size_t can represent). A large constant is used to ensure the remainder of the line, no matter how long, is consumed and discarded leaving std::cin either empty or with the first character of the next line (in a multi-line buffer) waiting to be read.
std::basic_istream::ignore can also read up to a delimiter character reading/discarding less than the whole line. That can be useful when reading separated fields, or in cases where you use a delimiter with getline() to read less than an entire line.
You either perform your read operation first and then call ignore() to discard unwanted characters to the end of the line, or you can call ignore() first with either a specified number of characters (default 1) or a delimiter to discard the beginning portion of a line up to the first character you want to began your read with.
As you have used it above, it will simply chop off the first character of whatever the user enters -- which does not seem to be what you want. In fact, ignore() isn't even needed above. Remove it and see if the missing character problem doesn't go away.

Does istream::ignore discard more than n characters?

(this is possibly a duplicate of Why does std::basic_istream::ignore() extract more characters than specified?, however my specific case doesn't deal with the delim)
From cppreference, the description of istream::ignore is the following:
Extracts and discards characters from the input stream until and including delim.
ignore behaves as an UnformattedInputFunction. After constructing and checking the sentry object, it extracts characters from the stream and discards them until any one of the following conditions occurs:
count characters were extracted. This test is disabled in the special case when count equals std::numeric_limitsstd::streamsize::max()
end of file conditions occurs in the input sequence, in which case the function calls setstate(eofbit)
the next available character c in the input sequence is delim, as determined by Traits::eq_int_type(Traits::to_int_type(c), delim). The delimiter character is extracted and discarded. This test is disabled if delim is Traits::eof()
However, let's say I've got the following program:
#include <iostream>
int main(void) {
int x;
char p;
if (std::cin >> x) {
std::cout << x;
} else {
std::cin.clear();
std::cin.ignore(2);
std::cout << "________________";
std::cin >> p;
std::cout << p;
}
Now, let's say I input something like p when my program starts. I expect cin to 'fail', then clear to be called and ignore to discard 2 characters from the buffer. So 'p' and '\n' that are left in the buffer should be discarded. However, the program still expects input after ignore gets called, so in reality it's only get to the final std::cin>>p after I've given it more than 2 characters to discard.
My issue:
Inputting something like 'b' and hitting Enter immediately after the first input (so 2 after the characters get discarded, 'p' and '\n') keeps 'b' in the buffer and immediately passes it to cin, without first printing the message. How can I make it so that the message gets printed immediately after the two characters are discarded and then << is called?
After a lot of back and forth in the comments (and reproducing the problem myself), it's clear the problem is that:
You enter p<Enter>, which isn't parsable
You try to discard exactly two characters with ignore
You output the underscores
You prompt for the next input
but in fact things seem to stop at step 2 until you give it more input, and the underscores only appear later. Well, bad news, you're right, the code is blocking at step 2 in ignore. ignore is blocking waiting for a third character to be entered (really, checking if it's EOF after those two characters), and by the spec, this is apparently the correct thing to do, I think?
The problem here is the same basic issue as the problem you linked just a different manifestation. When ignore terminates because it's read the number of characters requested, it always attempts to reads one more character, because it needs to know if condition 2 might also be true (it happened to read the last character so it can take the appropriate action, putting cin in EOF state, or leaving the next character in the buffer for the next read otherwise):
Effects: Behaves as an unformatted input function (as described above). After constructing a sentry object, extracts characters and discards them. Characters are extracted until any of the following occurs:
n != numeric_limits::max() (18.3.2) and n characters have been extracted so far
end-of-file occurs on the input sequence (in which case the function calls setstate(eofbit), which may throw ios_base::failure (27.5.5.4));
traits::eq_int_type(traits::to_int_type(c), delim) for the next available input character c (in which case c is extracted).
Since you didn't provide an end character for ignore, it's looking for EOF, and if it doesn't find it after two characters, it must read one more to see if it shows up after the ignored characters (if it does, it'll leave cin in EOF state, if not, the character it peeked at will be the next one you read).
Simplest solution here is to not try to specifically discard exactly two characters. You want to get rid of everything through the newline, so do that with:
std::cin.ignore(std::numeric_limits<std::stringsize>::max(), '\n');
instead of std::cin.ignore(2);; that will read any and all characters until the newline (or EOF), consume the newline, and it won't ever overread (in the sense that it continues forever until the delimiter or EOF is found, there is no condition under which it finishes reading a count of characters and needs to peek further).
If for some reason you want to specifically ignore exactly two characters (how do you know they entered p<Enter> and not pabc<Enter>?), just call .get() on it a couple times or .read(&two_byte_buffer, 2) or the like, so you read the raw characters without the possibility of trying to peek beyond them.
For the record, this seems a little from the cppreference spec (which may be wrong); condition 2 in the spec doesn't specify it needs to verify if it is at EOF after reading count characters, and cppreference claims condition 3 (which would need to peek) is explicitly not checked if the "delimiter" is the default Traits::eof(). But the spec quote found in your other answer doesn't include that line about condition 3 not applying for Traits::eof(), and condition 2 might allow for checking if you're at EOF, which would end up with the observed behavior.
Your problem is related to your terminal. When you press ENTER, you are most likely getting two characters -- '\r' and '\n'. Consequently, there is still one character left in the input stream to read from. Change that line to:
std::cin.ignore(10, '\n'); // 10 is not magical. You may use any number > 2
to see the behavior you are expecting.
Passing exact number of characters in buffer will do the trick:
std::cin.ignore(std::cin.rdbuf()->in_avail());

Why does std::istream::ignore not return when called on an empty stream?

std::cin is a global object, and as such I always want to set it to a good state before using it. However, when invoking ignore() on an unused cin the function doesn't return.
See sample code below. Execution doesn't reach line 8 (cout) without user intervention. In my testing this behavior is consistent with or without the second argument (the delimiter, I've tried '\n' and EOF).
I've been through a couple of online references, but I don't see why this happens.
#include <limits>
#include <iostream>
#include <string>
std::string readInput() {
std::string input = "";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "We never get here..." << std::endl;
std::getline(std::cin, input);
return input;
}
int main() {
std::string foo = readInput();
}
Why does ignore() not return in this case?
How can I safely reset and empty std::cin before use?
See the second argument '\n'. You are requesting to read characters up to and including a '\n' and ignore them. Since there is no '\n' on the stream, this means to block until one is received.
Hopefully it is clear that you should only make this call when it is known that there is a '\n' on the stream.
So , the answer to your second question is that before use, do nothing, since there is no data on the stream anyway.
The time to clear the stream is after reading some data from it; and then depending on which read operation you used, you will know whether or not there is a newline.
Note that there is no such operation "clear whatever is on the stream" (this is intentional design). Instead your operations would be things like "clear the remainder of the line", where "the line" is defined as up to the next newline character; and input would have come from a file that uses lines, or an interactive terminal where the user presses Enter.
As stated in the documentation:
ignore behaves as an UnformattedInputFunction. After constructing and checking the sentry object, it extracts characters from the stream and discards them until any one of the following conditions occurs: [...]
the next available character c in the input sequence is delim, as determined by Traits::eq_int_type(Traits::to_int_type(c), delim). The delimiter character is extracted and discarded. This test is disabled if delim is Traits::eof()
Therefore, it will trigger a call to underflow() of the corresponding stream buffer if the stream is empty, as ignore in your case is waiting for '\n'.
Note: When you want to make sure your stream buffer is entirely empty, you may call cin.rdbuf()->in_avail() to get the amount of characters still waiting to be extracted from the input buffer, thus being 0 if the buffer is empty. This however is highly implementation-dependent, as it will work e.g. with Visual Studio out of the box. For GCC on the other hand, you have to call cin.sync_with_stdio(false) before in order to turn own the internal buffering. It will not work with LLVM like this, though.

How to ignore line break after reading two ints with cin?

I am new to C++, I have practically started it today. Any way, I am facing a problem where the first line contains two integers, and the next lines contain operations to be done. It's a fairly weird problem, actually, so I won't go into the details. Well, I am having a problem with reading the first line, and then the follow up operations.
My code looks like this so far:
int m, j;
string comando;
string OPR
cin << m << l;
while (getline(cin, comando)) {
OPR = comando.substr(0, 3);
}
The problem is: Apparently, whenever I write both m and l in the same line, the \n stays in the buffer, and it get's read by the newline, causing a problem when I try to take the substring. I tried adding a char variable that would be read after m and l, which would, supposedly, get the \n. However, it is getting the first letter of the newline instead, which, then, messes up my code. I tried to see if I had any syntax errors or anything, but that isn't it. I also looked for ways to ignore the \n char, but everything I found was related to strings, or reading from files.
I know I could read the line, and then cast the two ints from string to int, but that seems like a bad way to do it (at least it would be a bad way to do it in C).
Anyways, if any one can help me, that would be awesome, thanks!
P.S.: I don't do a check before the substr operation because, by the definition of the problem, the line will have a 3-char operation, a space and then an integer.
A good place to look for tips for common problems like this is your favorite reference:
When used immediately after whitespace-delimited input, e.g. after int n; std::cin >> n;, getline consumes the endline character left on the input stream by operator>>, and returns immediately. A common solution is to ignore all leftover characters on the line of input with cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); before switching to line-oriented input.
From here.

Why doesn't whitespace act as a delimiter when printing strings with ostream operator<<?

I know that when writing code like std::cin >> some_var; , where some_var is a string variable, only the first word that was inputted will be stored in some_var. But I do not understand why std::cout << "something here"; does not only output "something". Am I missing something?
When reading input using cin >> some_var, the delimiter is space by default (you can change this though), while when printing, cout prints till its find \0 which is end of the string.
If you want to read till it finds \0 in the input stream, then you've to write this:
std::getline(std::cin, some_var, '\0');
You can give any other character as delimiter as third argument of std::getline function.
Note that there is a member function with same name getline which is slightly different than the one I used above which is a free standalone function.
Compare:
std::getline - free standalone function. An overloaded function is also available.
istream::getline - member function of std::istream
I used the first one.
It was deemed useful that cin, when reading into a string terminates at whitespace. But it wasn't deemed useful that only the first word is printed when you print a string.
After all you said print "something here" to cout· In the other case, you just said read something from cin. The choice between a word, between a line and between the whole content of stdin (until an EOF is received) is arbitrary and the design happens to be to read a word. That makes it easy to quickly read a record line like "john 10 2.15" (first read into string, then into an int, and then into a float). Use std::getline to read a whole line into a string.
Because when you take input from std::cin, it needs to know when to stop taking input. If it didn't stop at the first word, when would it stop? However, when you output a variable, the answer is easy- you output that one variable.
Yes... cin stops at a space because, by default, it thinks you want a word. cout doesn't follow the same restriction, because, well, why would it? Think about it for a second — would it make any sense whatsoever if printing out "Hello, world!" actually just printed out "Hello,"? Of course it doesn't make any sense. The developer knows what they want to output (at least, we hope :D).
I think they took a convention and stick to it. In the case of <<, it is clear that you specify what to be written. In the case of a >>, they have to decide where to stop. Newline? Maybe this is the most natural alternative, but they just decided to stop reading at a space.
The delimiters are different for cin and for cout. For cin, input is split at whitespaces, for cout, at end of lines. You can change those default delimiters though.