What the general purpose when using cin.clear? [duplicate] - c++

This question already has answers here:
Why would we call cin.clear() and cin.ignore() after reading input?
(4 answers)
Closed 5 years ago.
I am a beginner to c++, and I just can't wrap my head around whats cin.ignore & cin.clear, they make absolutely no sense to me. When you explain this to me, please be very descriptive

In C++ input processing, cin.fail() would return true if the last cin command failed.
Usually, cin.fail() would return true in the following cases:
anytime you reach the EOF and try to read anything, cin.fail() would return true.
if you try to read an integer and it receives something that cannot be converted to an integer.
When cin.fail() return true and error occurs, the input buffer of cin is placed in an "error state". The state would block the further input processing.
Therefore, you have to use cin.clear(). It would overwrite the current value of the stream internal error flag => All bits are replaced by those in state, if state is good bit all error flags are cleared.
For cin.ignore, first it would accesses the input sequence by first constructing a sentry object. After that, it extracts characters from its associated stream buffer object as if calling its member functions sbumpc or sgetc, and finally destroys the sentry object before returning.
Therefore, It commonly used to perform extracting and discarding characters. A classical cases of cin.ignore is that when you're using getline() after cin, it would leaves a newline in your buffer until you switch function. That why you MUST flush the newline out of the buffer.

std::cin.ignore() can be called three different ways:
No arguments: A single character is taken from the input buffer and discarded:
std::cin.ignore(); //discard 1 character
One argument: The number of characters specified are taken from the input buffer and discarded:
std::cin.ignore(33); //discard 33 characters
Two arguments: discard the number of characters specified, or discard characters up to and including the specified delimiter (whichever comes first):
std::cin.ignore(26, '\n'); //ignore 26 characters or to a newline, whichever comes first
source: http://www.augustcouncil.com/~tgibson/tutorial/iotips.html

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 do we need to use cin.ignore() before getline(cin, string)? [duplicate]

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 1 year ago.
Why do we need to use cin.ignore() before taking input in a string?
What is the backhand process? Why does it skip the input in a string (if we call getline function for more variables) if we don't use cin.ignore()?
You only need to use cin.ignore() when there's some previous input you haven't read. If there isn't, then you don't need to and it will cause you to ignore something you want. The most common case is to ignore a newline character the ended a previous line.
If someone types "foo<enter>bar" and you want to read "foo" then "bar", you need to ignore the <enter> between them (or use a function that does so automatically).
std::getline() only "skips" input if there is a leading newline in the stream which precedes the input you wish to read. This can come about if you previously performed a formatted extraction which left a residual newline. By default, std::getline() delimits extraction upon the acquisition of a newline character.
ignore() is a function which discards a certain amount of characters (by default the amount to discard is 1). If you use this preceding an unformatted extraction (like std::getline()) but following a formatted extraction (like std::istream::operator>>()) it will allow the data to be read as you expect because it will discard the residual newline.
I talk about this in detail in my answer here.

Why does string extraction from a stream set the eof bit?

Let's say we have a stream containing simply:
hello
Note that there's no extra \n at the end like there often is in a text file. Now, the following simple code shows that the eof bit is set on the stream after extracting a single std::string.
int main(int argc, const char* argv[])
{
std::stringstream ss("hello");
std::string result;
ss >> result;
std::cout << ss.eof() << std::endl; // Outputs 1
return 0;
}
However, I can't see why this would happen according to the standard (I'm reading C++11 - ISO/IEC 14882:2011(E)). operator>>(basic_stream<...>&, basic_string<...>&) is defined as behaving like a formatted input function. This means it constructs a sentry object which proceeds to eat away whitespace characters. In this example, there are none, so the sentry construction completes with no problems. When converted to a bool, the sentry object gives true, so the extractor continues to get on with the actual extraction of the string.
The extraction is then defined as:
Characters are extracted and appended until any of the following occurs:
n characters are stored;
end-of-file occurs on the input sequence;
isspace(c,is.getloc()) is true for the next available input character c.
After the last character (if any) is extracted, is.width(0) is called and the sentry object k is destroyed.
If the function extracts no characters, it calls is.setstate(ios::failbit), which may throw ios_base::failure (27.5.5.4).
Nothing here actually causes the eof bit to be set. Yes, extraction stops if it hits the end-of-file, but it doesn't set the bit. In fact, the eof bit should only be set if we do another ss >> result;, because when the sentry attempts to gobble up whitespace, the following situation will occur:
If is.rdbuf()->sbumpc() or is.rdbuf()->sgetc() returns traits::eof(), the function calls setstate(failbit | eofbit)
However, this is definitely not happening yet because the failbit isn't being set.
The consequence of the eof bit being set is that the only reason the evil-idiom while (!stream.eof()) doesn't work when reading files is because of the extra \n at the end and not because the eof bit isn't yet set. My compiler is happily setting the eof bit when the extraction stops at the end of file.
So should this be happening? Or did the standard mean to say that setstate(eofbit) should occur?
To make it easier, the relevant sections of the standard are:
21.4.8.9 Inserters and extractors [string.io]
27.7.2.2 Formatted input functions [istream.formatted]
27.7.2.1.3 Class basic_istream::sentry [istream::sentry]
std::stringstream is a basic_istream and the operator>> of std::string "extracts" characters from it (as you found out).
27.7.2.1 Class template basic_istream
2 If rdbuf()->sbumpc() or rdbuf()->sgetc() returns traits::eof(), then the input function, except as
explicitly noted otherwise, completes its actions and does setstate(eofbit), which may throw ios_-
base::failure (27.5.5.4), before returning.
Also, "extracting" means calling these two functions.
3 Two groups of member function signatures share common properties: the formatted input functions (or
extractors) and the unformatted input functions. Both groups of input functions are described as if they
obtain (or extract) input characters by calling rdbuf()->sbumpc() or rdbuf()->sgetc(). They may use
other public members of istream.
So eof must be set.
Intuitively speaking, the EOF bit is set because during the read operation to extract the string, the stream did indeed hit the end of the file. Specifically, it continuously read characters out of the input stream, stopping because it hit the end of the stream before encountering a whitespace character. Accordingly, the stream set the EOF bit to mark that the end of stream was reached. Note that this is not the same as reporting failure - the operation was completed successfully - but the point of the EOF bit is not to report failure. It's to mark that the end of the stream was encountered.
I don't have a specific part of the spec to back this up, though I'll try to look for one when I get the chance.

incorrect results with gets () due to the stray \n in istream BUT not with scanf() or cin?

In the program printed below the problem with gets () is that it takes the data for the first time only, and every subsequent call results in a null, due to the stray \n in the istream left while entering the number.
main()
{
char name[20];
int number;
for(int i=0;i<5;i++)
{
printf("enter name");
gets(s);
printf("enter phone number");
cin>>a;
}
}
Now my question is that why isn't the same happening for when I use scanf() or cin ? I mean whats the difference in the way cin and gets() takes their values which enables cin (and scanf ) to successfully leave that stray \n but not gets() ?
PS: I know about fgets(), and that gets() is deprecated and its ill-effects, and generally dont use it as well.
You're mixing line-oriented input with field-oriented input. Functions like gets(), fgets(), etc read lines. They don't care necessarily the contents of the line, but they'll read the whole line (provided there's space for it in some cases).
Field oriented inputs like cin's >> operator and scanf() don't care about lines, they care about fields. A call like scanf("%d %d %d", &x, &y, &z); doesn't care if they're on the same line or 3 separate lines (or even if you leave blank lines).
These field oriented input functions tend to leave behind newline characters that will confuse line oriented input functions. In general, you should avoid mixing the two, If you want to do both, it's often useful to read the line then use sscanf() or stringstream to do field based input from it. This also makes recovering from bad inputs a bit easier, and you won't have to worry about whether or not there are extra '\n' chars waiting for your next input function.
scanf and cin >> both read fields delimeted by whitespace, and ignore leading whitespace. Now whitepsace is spaces, tabs, AND NEWLINES, so extra newlines in the input doesn't bother them. More importantly, after reading something, they DO NOT read any of the following whitespace, instead leaving it on the input for the next call to read.
Now with scanf, you can tell it explicitly to read (and throw away) as much whitespace as it can by using a space at the end of the format string, but that will work poorly for interactive input, as it will KEEP trying to read until it gets some non-whitepsace. so if you change the end of your loop to:
printf("enter phone number");
scanf("%d ", &a);
it will seem to hang after entering the phone number, as its waiting for you to enter some non-whitespace, which will ultimately be read by the next loop iteration as the next name.
You CAN use scanf to do what you want -- read and consume the text following the phone number up to the newline -- but its not pretty:
scanf("%d%*[^\n]", &a); scanf("%*1[\n]");
You actually need two scanf calls to consume the newline as well as any space or other cruft that might be on the line.
gets(), unlike fgets(), should replace a terminating newline with a null character.
This is from gets() man page:
The gets() function shall read bytes from the standard input stream, stdin, into the array pointed to by s, until a is read or an end-of-file condition is encountered. Any shall be discarded and a null byte shall be placed immediately after the last byte read into the array."
Though fgets() will pass the newline unchanged:
The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, or a is read and transferred to s, or an end-of-file condition is encountered. The string is then terminated with a null byte.
So, seems that your implementation is unconforming... Mine works as stated.