getline and testing EOF at once
Always test whether input succeeded after the read attempt! The stream cannot know what you are attempting to do. It can only report whether the attempts were successful so far. So, you'd do something like
if (std::getline(stream, line)) {
// deal with the successful case
}
else {
// deal with the failure case
}
In the failure case you might want to use use eof()
to determine whether the failure was due reaching the end of the stream: Having reached the end of file and, thus, std::ios_base:eofbit
being set is often not an error but simply the indication that you are done. It may still be an error, e.g., when it is known how many lines are to be read but fewer lines are obtained.
How to check if EOF (after using getline)
I solved my problem, just in case anyone wants to know. It's not as memory efficient as it could be, but it functions:
// Reads the file, checks if it's due, and if it's due prompts user to either save or delete the task.
// Captures a clean copy of the line, in its entirety, and stores it to workingString.
while(getline(checkTasks,workingString)){
countTheDays = 0;
// Handles newline characters.
char nlcheck;
checkTasks.get(nlcheck);
if(nlcheck == '\n'){
}
else{
checkTasks.unget();
// Breaks that line up into more usable pieces of information.
getline(check2,tName, '\t');
getline(check2,tDate, '\t');
getline(check2,trDate, '\t');
getline(check2,tComplete, '\n');
// Converts the string from of these pieces into usable integers.
stringstream(tDate.substr(0,tDate.find_first_of('/'))) >> year; stringstream(tDate.substr(tDate.find_first_of('/')+1,tDate.find_last_of('/'))) >> month; stringstream(tDate.substr(tDate.find_last_of('/')+1,tDate.length()-1)) >> day;
stringstream(tComplete) >> checkComplete;
stringstream(trDate) >> checkReminder;
// Adds the number of days until your task is due!
if(year != date[0]){
for(int i = date[1]; i <= 12; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays-= date[2];
for (int i = 1; i<= month; i++){
countTheDays +=System::DateTime::DaysInMonth(year, i);
}
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else if(month != date[1]){
for(int i = date[1]; i <= month; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays -= (date[2]);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else{
countTheDays+= System::DateTime::DaysInMonth(date[0], month);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
countTheDays -= date[2];
}
// If the task is nearing it's due date (the time frame specified to be notified) it'll notify user.
if(countTheDays <= checkReminder){
if( countTheDays < 0){
cout << endl << endl << tName << " is past due!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
else{
cout << endl << endl << tName << " is due in " <<countTheDays << " days! Don't forget!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
// If user doesn't want to be reminded, begins process of converting that line in the file to usable info
// and 'overwriting' the old file by creating a new one, deleting the old one, and renaming the new one.
if(continueToRemind == "n" || continueToRemind == "N"){
fileModified = true;
// Adds workingString to deleteTasks[] to be compared against later.
deleteTasks.push_back(workingString);
}
}
}
}
int match = 0;
// Iterates through tempTasks.dat and compares lines to workingString.
while(getline(tasksClone, testBuffer)){
for(int i = 0; i< deleteTasks.size(); i++){
// If a match is found, it sets the match flag to delete that line.
if(testBuffer == deleteTasks[i]){
match = 1;
}
}
// Deletes that task.
if(match == 1){
//Do nothing, erasing the task
}
// If EOF, writes only the task, without a newline character.
else if(tasksClone.eof()){
saveTasks << testBuffer;
}
// If !EOF, also writes a newline character.
else{
saveTasks << testBuffer << '\n';
}
match = 0;
}
c++ getline() and file EOF
The problem is when infile.getline
reads the last line (i.e. it reads until EOF), while(infile)
will still evaluate to true, causing the loop to be run again. However, since infile
has read the entire file, infile.getline
will fail, and str
will become an empty string. However, since your original code overwrites the first character, it gets rid of the null terminator, so it winds up reusing the contents from last time.
Instead, you want something like:
while (infile.getline(str, strSize)) {
if (sequenceNum>469)
...
}
How to know if next getline is EOF C++
You could do something like this:
Declare variable bool reach;
getline(file, line);
if(file.eof()) reach = true;
What's actually happens when we try to extract line in file after which `eof` character is present with istream::getline() and std::getline()
To quote the standard, section 21.3.3.4 inserters and extractors [string.io]:
Clause 6:
[…] After constructing a
sentry
object, if thesentry
converts totrue
, callsstr.erase()
and then extracts characters fromis
and appends them tostr
[…] until any of the following occurs:
- end-of-file occurs on the input sequence (in which case, the
getline
function callsis.setstate(ios_base::eofbit))
.- […]
Section 29.7.4.1.3 Class basic_istream::sentry
:
explicit sentry(basic_istream<charT, traits>& is, bool noskipws = false);
Effects: Ifis.good()
isfalse
, callsis.setstate(failbit)
[…]
If, after any preparation is completed,is.good()
istrue
,ok_ != false
otherwise,ok_ == false
. During preparation, the constructor may callsetstate(failbit)
[…]
explicit operator bool() const;
Returns:ok_
So, what is happening with the string version:
- You extract the last string. This sets eofbit, but not failbit
- You getline again
- getline constructs a sentry
- The sentry checks
is.good()
. This is false because eofbit is set - The sentry sets the failbit and sets its member ok_ to false
- The getline function checks if the sentry is true (operator bool). This is false
- The getline function returns before clearing your old string
Section 29.7.4.3 Unformatted input functions
Clause 21 (this is about the C-string version):
In any case, if
n
is greater than zero, it then stores a null character (usingcharT()
) into the next successive location of the array
The rest of the wording is similar to the string version. In other words, the C-string version of getline always stores a '\0'
character, even if it failed. The std::string
version does not, presumably because it doesn't introduce the same memory safety issues that you have with the C version if you forget to check the failbit.
How to check if EOF comes first in getline() function in C?
As @wildplasser suggested, use the following code.
int main(void){
printf("Type something:\n");
while(1){
char * array = NULL;
size_t size = 0;
ssize_t read = getline(&array, &size, stdin);
if((read < 0 || (strlen(array) == 0)) && feof(stdin) ){
free(array);
return 0;
};
/* do something else */
free(array);
}
return 0;
}
C++ std::getline() doesn't set the EOF flag
Same reason as why eof()
in a loop condition does not work. Notice that your code is basically the exact same as while(!graph_file.eof())
since you're checking the condition at the start of the loop, which is exactly what a normal while loop does.
eof()
only gets set on the first attempt to read past the end of the file. If there is a newline at the end which stops the input, the flag does not get set.
The fix is in the link at the top of this answer.
Related Topics
Is There Any Lame C++ Wrapper\Simplifier (Working on Linux MAC and Win from Pure Code)
Program Behaving Strangely on Online Ides
Determining Exception Type After the Exception Is Caught
Does New[] Call Default Constructor in C++
Popen Simultaneous Read and Write
C++: Deep Copying a Base Class Pointer
Configuring the Gcc Compiler Switches in Qt, Qtcreator, and Qmake
How Is Vector Implemented in C++
Are There Any MACros to Determine If My Code Is Being Compiled to Windows
How to Make a Heterogeneous Boost::Map
"Launch Failed. Binary Not Found." Snow Leopard and Eclipse C/C++ Ide Issue
Should I Copy an Std::Function or How to Always Take a Reference to It
How Large Is a Dword with 32- and 64-Bit Code
Determine If Type Is a Pointer in a Template Function
What Exactly Is a 'Side-Effect' in C++
Return Type Covariance with Smart Pointers
Differencebetween a MACro and a Const in C++
What Is the Fastest Method for High Performance Sequential File I/O in C++