2

This code always prints the last line of the file. I expected it to print all the text, one line at a time, from the file. Any idea why it doesn't work?

string filename;
cout << "File to read: ";
cin >> filename;

ifstream afile;
afile.open(filename.c_str());

string line;
while(!afile.eof()) {
    getline(afile, line);
    cout << line;
}

afile.close();

Trying it this way does the same thing:

for (string line; getline(afile, line);) {
    cout << line;
}

Maybe this is an issue with my terminal? This works...

for (string line; getline(afile, line);) {
    cout << line << endl;
}
David Mulder
  • 6,276
  • 10
  • 40
  • 59
  • http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong – chris May 21 '13 at 01:29
  • I'm not checking for eof in the for loop, why does it do the same thing? – David Mulder May 21 '13 at 01:34
  • What goes wrong? What happens? – Victor Sand May 21 '13 at 01:35
  • 1
    You are checking for eof() as the controlling statement of a loop, which is exactly what's wrong. – Jerry Coffin May 21 '13 at 01:36
  • 1
    @David: the `for` loop will work - perhaps you tripped up somewhere - e.g. had a compile error you didn't notice and accidentally ran the `while(!eof)` binary again...? Please retest. – Tony Delroy May 21 '13 at 01:37
  • It only prints out the last line, but I think I might have figured it out... If I change it to cout << line << endl; then it works. Apparently it's writing over top of each line? – David Mulder May 21 '13 at 01:37

2 Answers2

1

The problem is that only the last line is printed. Correct?

  1. I suggest that you add std::endl in your while loop. It can make the issue more clear. Sometimes the output can be confusing.
  2. You can also check the line-delimiting character in your input file. '\n' is the default delimiter for getline. If a different character is used, specify it as getline's 3rd parameter.
ajtomato
  • 26
  • 3
  • What's odd is that it's over writing each line on the terminal as it prints. If I add an endl after each cout, then everything works as expected. – David Mulder May 21 '13 at 02:20
  • If the last line is shorter than the one before, it's more obvious. Then I see that it actually wrote overtop of the line (because I can see the chars from the previous line appended on the end). – David Mulder May 21 '13 at 02:21
  • It seems as stream buffer overflow. You can check the state of the stream. It is helpful to find what happens. You can use std::cout.rdstate(). – ajtomato May 21 '13 at 05:53
1

From cplusplus.com:

If the delimiter is found, it is extracted and discarded, i.e. it is not stored and the next input operation will begin after it.

Since your original code snippet doesn't insert any extra newlines itself, there is nothing making the output to the terminal go to the next line. When the output runs out of horizontal space what happens next is up to the terminal. I'm not sure what terminal you're using but in your case, it just wraps the cursor back to the first character on that line without a linefeed. On a windows command shell, it just wraps around to the next line.

Also note that:

while(!afile.eof()) {
    getline(afile, line);
    cout << line;
}

is a common antipattern. As already pointed out, more appropriate would be:

while(getline(afile, line)) {
    cout << line << '\n';
}

The file stream only becomes false after you've reached eof and try to read from it.

greatwolf
  • 18,899
  • 13
  • 64
  • 102