How to stop getline() loop over cin automatically - c++

Hello my code is the following:
while (getline(cin, line))
{
// process on line
}
so this causes the user to keep putting lines until he inputs ^z.
How can I make it so that it automatically stops without user intervention? For example, when the user pastes the input lines without ^z, I need the above loop to do the processing and then stop.

std::getline will extract until:
EOF was encountered, which sets eofbit
A delimiter was encountered (no flag is set, so the next extraction won't fail)
You encountered std::string::max_size, which sets failbit
An error occurred
You can't have the user copy/paste and expect the program to automatically know that the user is done. What if the input was something else, like a file?
RE comment: you can still pipe input from a file and the program can't tell the difference.
# will stop extraction via EOF
cat file | ./a.out

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 .

file exception and cursor movement c++

I use exception handling while reading from a file to determine if the part I wish to store in a variable is of the correct type (eg. I don't want to store a string in a double variable), but when the exception occurs, the cursor won't go to the next line. Is there any possible way to do so?
If you have enabled exception for incorrect/failed input, the first wrong character in the input stream will raise the exception.
If your error processing consist of skipping the rest of the line to resume with the procesing of the next line, you have to clear the error status and then to ignore the unread chars of the line. Add the following in your exception processing code:
InputFile.clear(); // without this, every subsequent file op would fail
InputFile.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
You should however take care, because >> reading from streams might skip newlines as well, so that a missing data might position you already on the next line. A safer approach would be to read the stream line by line with std::getline() and parse each line with a stringstream.

c++ endless loop reading file created redirecting command output

I'm writing a code in which I check a given directory for new files or directories. New in my situation is regarded to last time the code has been run in that directory. So I create a log file and then I acquire the log in a string vector. The code is the following:
ifstream Finp;
string directory;
vector <string> newfilelist;
system( ("ls -B "+directory+" > "+directory+"filelist.log").c_str() );
Finp.open( (directory+"filelist.log").c_str() );
while ( true ) {
string stmp;
Finp >> stmp;
if( Finp.eof() ) break;
newfilelist.push_back( stmp );
}
Now what's happening is the following:
1) if the log "filelist.log" already exists, everything runs smoothly
2) if the log "filelist.log" does not exist, it is correctly created but when the code opens the file and starts acquiring it, it gets stuck in a loop and the stmp string is endlessly empty (as if the file has no eof() and yet is empty!). what is intresting is the fact that if I place a random system command before opening the log everything runs smoothly!
What am I missing?
I think that, the only thing you would need to change is that nasty while(true) loop to while(file<< to_variable). This would only read data IF there is some.
The eof() is actually quite deceiving. You would guess that it is called right at the end of the file. Though true, when you try to read from the file at the >> operation the pointer in the stream will jump back before the EOF and try to read what is there.
There is quite the few threads here discussing just EOF and using that as a condition for a loop.
If the file does not exist, Finp.open() will basically fail, and checking Finp.eof() is meaningless. Before even attempt to enter a loop to read or check eof, you need to check the Finp status with Finp.good() and then proceed with reading only if this method returns true.

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→

Whitespace at end of file causing EOF check to fail in C++

I am reading in data from a file that has three columns. For example the data will look something like:
3 START RED
4 END RED
To read in the data I am using the following check:
while (iFile.peek() != EOF) {
// read in column 1
// read in column 2
// read in column 3
}
My problem is that the loop usually does an extra loop. I am pretty sure this is because a lot of text editors seem to put a blank line after the last line of actual content.
I did a little bit of Googling and searched on SO and found some similar situations such as Reading from text file until EOF repeats last line however I couldn't quite seem to adapt the solution given to solve my problem. Any suggestions?
EOF is not a prediction but an error state. Hence, you can't use it like you're using it now, to predict whether you can read Column 1, 2 and 3. For that reason, a common pattern in C++ is:
while (input >> obj1 >> obj2) {
use(obj1, obj2);
}
All operator>>(istream& is, T&) return the inputstream, and when used in boolean context the stream is "true" as long as the last extraction succeeded. It's then safe to use the extracted objects.
Presuming iFile is an istream:
You should break out of the loop on any error, not only on EOF (which can be checked for with iFile.eof(), BTW), because this is an endless loop when any format failure sets the stream into a bad state other that EOF. It is usually necessary to break out of a reading loop in the middle of the loop, after everything was read (either successfully or not), and before it is entered.
To make sure there isn't anything interesting coming anymore, you could, after the loop, reset the stream state and then try to read whitespace only until your reach EOF:
while( !iFile.eof() )
{
iFile >> std::ws;
string line;
std::getline(iFile,line);
if(!line.empty()) error(...);
}
If any of the reads fail (where you read the column data), just break out of the while loop. Presumably you are then at the end of the file and reading the last 'not correct' line
Maybe you'll consider it a good idea to handle whitespace and other invalid input then. Perhaps some basic validation of columns 1,2,3 would be desirable as well.
Don't worry about the number of times that you loop: just validate your data and handle invalid inputs.
Basically, check that you have three columns to read and if you don't decide if it's because the file is over or because of some other issue.