Whitespace at end of file causing EOF check to fail in C++ - 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.

Related

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.

While loop construct in combination with getline function that continues until EOF

I am in a bind right now and the most frustrating thing about this is that I know what the problem is but, I cannot fix it :(...
My goal is to ultimately use getline to read lines of strings from redirected input (from a text file) and keep going until EOF is reached.
Example text file (contents):
Hello World!
Good Bye.
My source code(only includes the section where it will not work):
while (!(getline(std::cin, s_array)).eof()){ // it won't read second line
//do some awesome stuff to the first line read!
}
As far as I know, getline reads everything upto the newline and stops so how do we get it to keep reading because it always stops at Hello World!.
Use while (getline(std::cin, s_array)) { } instead.
std::getline() returns istream&, and istream::operator void*() makes it evaluated as false whenever any error flag is set.
You should definitely read Joseph Mansfield's blog post titled "Don't condition input on eof()" which describes this pitfall in details and provides a well justified guideline.

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.

No `while (!my_ifstream.eof()) { getline(my_ifstream, line) }` in C++?

On this website, someone writes:
while (! myfile.eof() )
{
getline (myfile,line);
cout << line << endl;
}
This is wrong, read carefully the documentation for the eof()
memberfunction. The correct code is this:
while( getline( myfile, line))
cout << line << endl;
Why is this?
There are two primary reasons. #Etienne has pointed out one: reading could fail for some reason other than reaching the end of the file, in which case your first version will go into an infinite loop.
Even with no other failures, however, the first won't work correctly. eof() won't be set until after an attempt at reading has failed because the end of the file was reached. That means the first loop will execute one extra iteration that you don't really want. In this case, that'll just end up adding an extra blank (empty) line at the end of the file. Depending on what you're working with, that may or may not matter. Depending on what you're using to read the data, it's also fairly common to see the last line repeated in the output.
A stream operation (such as reading) can fail for multiple reasons. eof() tests just one of them. To test them all, simply use the stream's void *conversion operator. That's what's done in the second snippet.

Trying to Read a Line of Keyboard Input in C++

I mam trying to complete a college assignment in C++ and am having trouble with what should be a very basic operation. I am trying to read a string of characters from the keyboard. This is the relevant code:
string t;
cout << endl << "Enter title to search for: ";
getline(cin, t, '\n');
I understand, that the last line is supposed to read the input buffer (cin , in this instance) and store the character in the 't' string until it reaches a new line character and then continue the program flow.
However, when I run my code in XCode, it just sort of jumps over the getline function and treats 't' as an empty string.
What's going on? I tried using cin >> t but that just read characters forever - Why cant I get this to behave?
The reason that the input operation apparently is skipped, is most probably (that means, ignoring possible peculiarities of a bugsy XCode IDE) that you have performed some input earlier and left a newline in the input buffer.
To fix that, make sure that you have emptied the input buffer after each input operation that logically should consume a line of input.
One easy way is to always use getline into a string, and then use e.g. an istringstream if you want to convert a number specification to number type.
Cheers & hth.,
From the docs page it looks like you want
cin.getline(t,256,'\n');
or something similar.
This sounds like an issue with the way Xcode is running your program. Try running your program directly from the terminal, and see if this is sufficient to fix your issue.