istream_iterator ignoring EOF (Ctrl+D) when reading chars - c++

I'm trying to use istream_iterator for reading characters from cin. I've read that pressing Ctrl+D sends an EOF character which ends the input stream. Unfortunately, something is going wrong with it. Here's my code:
#include <iterator>
int main()
{
using namespace std;
istream_iterator<char> it(cin), eos;
while (it != eos) clog << *(it++);
}
I'm running it and typing: as df, then pressing Ctrl+D.
It outputs only asd without the last f and then hangs waiting for input. When I type gh and press Ctrl+D again, it prints the remaining f at last, and the g from next input, but again without the last h. And when I finally press Ctrl+D without typing anything, it prints the remaining h and exits.
I expected it to read asdf and exit, since I already pressed Ctrl+D at the end of this first sequence.
Why is it still waiting for input after getting EOF?
Why it doesn't print the last character read before EOF?
And why it exits only when I press Ctrl+D without typing anything before?
How does this loop need to change to make it behave in the way I expect? (i.e. stop reading immediately after getting Ctrl+D sequence in the input, no matter I typed anything before or not, and reading all characters up to the EOF).

Input iterators require special care. Rewrite your loop this way and the behavior will become similar to any other character input loop:
while (it != eos)
{
clog << *it;
it++;
}
That will take care of "Why it doesn't print the last character"
PS: as for EOF in the middle of the line, it is the POSIX-mandated behavior:
When received, all the bytes waiting to be read are immediately passed to the process without waiting for a newline, and the EOF is discarded. Thus, if there are no bytes waiting (that is, the EOF occurred at the beginning of a line), a byte count of zero shall be returned from the read(), representing an end-of-file indication.

On Unix-like systems, typing Ctrl+D triggers an end-of-file condition only at the beginning of a line (i.e., immediately after typing Enter. To trigger an end-of-file condition in the middle of a line, type Ctrl+D twice.

Related

Ending a while loop in command prompt

This is an excerpt from the Competitive Programmer's Handbook by Antti Laaksonen:
If the amount of data is unknown, the following loop is useful:
while (cin >> x) {
// code
}
This loop reads elements from the input one after another, until
there is no more data available in the input.
My question is how do we end such a loop in the command prompt, where the prompt takes one input at a time? By pressing enter, the prompt asks for new input and not terminating the input.
Edit: I have tried using ctrl + D/Z but I am getting this:
In order for that loop to end, cin needs to enter a failed state. That will cause it to evaluate to false and stop the loop. You have a couple ways you can do that. First is to send bad input, which will cause cin to fail and end the loop. Since you are excepting integers, you could just input a letter and that will cause it to break.
Another option is to send the EOF (end of file) signal to cin You can do that using ctrl+D (windows) or ctrl+Z (linux) and the pressing enter. cin will stop reading once it sees it has reachged the EOF and it will enter a failed state and cause the loop to end.
It should be noted that with both of these options that if you want to use cin again after you do this you will need to call clear() to remove the error flags and if you entered bad input, you will need to use ignore() to remove the bad input from the stream.
My question is how do we end such a loop in the command prompt, where the prompt takes one input at a time?
Note that cin >> x; returns cin. This means when you write
while(cin >> x)
you do the >> operation into x and then check cin.
When the user enters an input whose type differs from the type of variable x, then this while loop will end automatically. This is because cin will not be in a valid state anymore and hence cin >> x will become false . Basically the loop ends when the state of the stream is set to failed. Like supplying a different type value or when EOF is encountered.
There is other way to end such a loop from inside the while block by using break .

in c++ program after pressing enter , "cin" will feed all Variables

I have a program that takes two numbers and shows them on the screen.
However, when I hit "enter" after I input the first number, my program shows the answers before letting me input the second number.
Why does this happen?
int main()
{
int n1;
float n2;
cin>>n1;
cin>>n2;
cout<<"int n:"<<n1<<endl<<"float n:"<<n2;
return 0;
}
I wanna input 0.25 and 35 but when I write 0.25 and hit enter suddenly shows the answer "int: n:0 float n:0.25" it doesn't let me write second num. my os is Win10 and this program compiled with DevCpp
It works when both variables are ints.
There is no difference between cin>>n1; cin>>n2; and cin >> n1 >>n2. Enter key only serves as signal to sychronize input buffer and stream buffer. cin doesn't input per line, it parses buffer when there is available volume of data. If parse incomplete, it waits. If parse can't be done, it stops and state bit changes. To continue parsing you have either ignore or clear part or whole buffer content.
Something wrong was entered in first line, causing cin to go into bad() state. Edge case might happen if you're running program through a remote terminal, some incorrect character could slip in, e.g. ^M generated by new line from Windows would break cin stream on Linux. That's also case if you input from a file which was saved on different platform. On Windows line ends consist of two characters, #10 and #13. On linux steams expect only #13 as a new line and buffer flush signal, #10 is an unexpected character.
Edit (after OP gave information about input data):
"0.25" would be parsed as "0" and ".25", that expected and documented stream behavior. Parsing for n1 had stopped as soon as stream encountered character which doesn't fit int pattern, which could be space, end of line, alphabetic or punctuation. Period considered a punctuation in this case
Then it tries to get a float from stream input and buffer contains ".25". It's a legal float notation and it gets assigned to n2.
When you have both "int", you cannot get second value at all with same input, it always will be 0, because cin locks up in bad state, i.e. method its istream::good() returns false. You have to check state of stream after reading variables. Any further formatted reading that wouldn't be able to parse .25 wouldn't advance stream past that point.
If you want to read from stream exclusively line by line, you have to use istream::getline() method to get the string. There is also method get which can acquire content of stream and ignore which allows to discard part of stream.

When the input will stop?

Hi guys i have the following question:
string s;
std::cout << "give me a string" << std::endl;
while (std::cin >> s){
std::cout << "give me a string" << std::endl;
}
cin.clear();
if s was an integer then i know that if i typed a char then the while would break. If it was an integer and typed a double the same would happened. But what about strings ?? Somewhere I read that in windows (as I am writting at netbeans in windows) you have to press ctrl+z and then it stops as it is taken as a false string. But when i do this , the process freezes and nothing happens.
You need to send the EOF signal, which in Netbeans is Ctrl + D.
However, hitting Enter twice will result in the condition of your loop to resolve in false, causing the loop to stop. That's excpected: How is "std::cin>>value" evaluated in a while loop?
If that doesn't work, use Ctrl + z and a newline character, which is the EOF signal in Windows, as stated here. Ctrl + D is for Linux though, but it works in your case.
The EOF signal closes the input stream, thus breaking the loop.
Moreover, in Netbeans (if the above doesn't work) it seems that you need to run your application from the command prompt to achieve this. Another attempt would be to "press Ctrl + z after pressing Enter", as stated here.
The loop will stop when the input stream is closed.
If you run the program from a shell, then the input stream may be open indefinitely. Exactly how you would close the stream in a terminal, depends on what terminal you are using.
In UNIX, the stream is closed when you send empty input. ctrl + d is the standard key combination for sending (flushing) the input to the stream (^d is the ASCII control code EOT, end of transmission). Pressing enter also sends the input, but it also inserts the end of line character, so it is not possible to use it to send empty input.
ctrl + z is similar in windows, but it has different behaviour (wikipedia):
The EOT character in Unix is different from the Control-Z in DOS. The DOS Control-Z byte is actually sent and/or placed in files to indicate where the text ends. In contrast the Control-D causes the Unix terminal driver to signal the EOF condition, which is not a character, while the byte has no special meaning if actually read or written from a file or terminal.

scanf(%s) an issue with EOF

Im using scanf because we must use it.
the problem is the following :
(thats just an example of the problem):
int main() {
char ch [10]={0};
scanf("%s",ch);
printf("%s",ch);
}
if i run the program and enter for example : word^Z
when ^Z is EOF.
the program stays in place, stuck in the scanf, althogh i did type word then ctrl+z then Enter. but somehow it stays in the scanf, its the same thing with redirection, like its not a problem with ctr+z or anything.
i hope that i can get some help
thanks in advance,
totally apprecaite it :)
scanf uses whitespace as a delimiter to store the read data into various fields. From the command line, entering ControlZ, then Enter only puts the EOF character into the input stream and scanf() continues waiting for whitespace. If you hit Enter again, scanf will receive the whitespace character, and everything including the EOF will be stored into the ch array.
Here's a sample run. The first line is the input, and the second line is the output.
Hello^Z
Hello→

Why do I have to press enter Twice?

For some reason in my program when I reach a certain spot, I have to press Enter twice in order to get it to submit. I added the clear to keep it from skipping input and the ignore() to keep it from keeping any extra characters in the buffer. I enter my input and then it drops down to a new line, I hit Enter again and it enter the input and continues the program no problem but I'm wondering why. Here's a code snippet:
cin.ignore();
cout << "Enter Student Major (ex. COSC): ";
cin.getline(student.major, 6);
for(int i = 0; i < sizeof(student.major); i++)
student.major[i] = toupper(student.major[i]);
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
Any suggestions?
It seems to me that you are tossing too many cin.ignore() around, not knowing exactly why they are needed and when to put them there.
There are two common circumstances where cin.ignore() is needed to "make input work right":
when mixing formatted and unformatted input;
to recover from a formatted input error.
In both cases, you want to get rid of spurious characters from the input buffer; if there isn't any such character (which is probably what happens in your program), cin.ignore() will pause the execution and wait for user input - after all, you asked it to ignore some characters, and dammit, it will obey to its orders.
(although ignore() by default would "eat" just one character, whatever it may be, the execution is paused until a newline is found because by default cin is line buffered - new input is not examined until a newline is recieved)
Case 1:
cin.ignore() calls are often needed if you are performing an unformatted input operation (like getline) after performing a formatted input operation (i.e. using the >> operator).
This happens because the >> operator leaves the newline in the input buffer; that's not a problem if you are performing only formatted input operations (by default they skip all the whitespace before trying to interpret the input), but it's a problem if afterwards you do unformatted input: getline by default reads until it finds a newline, so the "spurious newline" left will make it stop reading immediately.
So, here you will usually call cin.ignore(...) call to get rid of the newline just after the last formatted input operation you do in a row, guaranteeing that the input buffer is empty. Afterwards, you can call getline directly without fear, knowing that you left the buffer empty.
It's a bad idea, instead, to put it before any getline, as you seem to do in your code, since there may be code paths that lead to that getline that have the input buffer clean, so the ignore call will block.
Case 2:
when istream encounters an error in a formatted input operations, it leaves the "bad" characters in the buffer, so if you retry the operation you get stuck endlessly, since the offenders are still there. The usual clear()/ignore() idiom comes to the rescue, removing the whole offending line from the input buffer.
Again, you don't put the clear()/ignore() sequence at random, but only after you get an input error from a formatted input operation (which sets the failbit of the stream).
Now, aside from these cases, it's uncommon to use cin.ignore() (unless you actually want to skip characters); don't spread it around randomly "just to be safe", because otherwise you will encounter the problem you described.
The answer can be found here.
The extraction ends when n characters have been extracted and discarded or when the character delim is found, whichever comes first. In the latter case, the delim character itself is also extracted.
So in your case, the program will not continue until a '\n' character is received.
I think cin.ignore(numeric_limits<streamsize>::max(), '\n'); is expecting a \n in the input and it doesn't find it, so you have to press Enter again for it to find it.