Checking for Eof in String::Getline

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 the sentry converts to true, calls str.erase() and then extracts characters from is and appends them to str […] until any of the following occurs:

  • end-of-file occurs on the input sequence (in which case, the getline function calls is.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: If is.good() is false, calls is.setstate(failbit)
[…]
If, after any preparation is completed, is.good() is true, ok_ != false otherwise, ok_ == false. During preparation, the constructor may call setstate(failbit)
[…]

explicit operator bool() const;
Returns: ok_

So, what is happening with the string version:

  1. You extract the last string. This sets eofbit, but not failbit
  2. You getline again
  3. getline constructs a sentry
  4. The sentry checks is.good(). This is false because eofbit is set
  5. The sentry sets the failbit and sets its member ok_ to false
  6. The getline function checks if the sentry is true (operator bool). This is false
  7. 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 (using charT()) 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



Leave a reply



Submit