0

Possible Duplicate:
End of File in C++

I wrote a function to read data from a .txt file, but when I call it, it keeps crashing. Here's the code:

void beolvas(vector<int> &charge, vector<int> &deliver, vector<Robot*> &robots) {
    string s;
    ifstream f;

    do {
        cout << "Add meg a filenevet" << endl;
        cin >> s;
        f.open(s.c_str());
    } while (!f.good());

    cout << "adatok beolvasasa..." << endl;

    int napok;
    if (!(f >> napok)) throw 1;
    charge.resize(napok);
    deliver.resize(napok);

    for (int i = 0; i<napok; i++) {
        if (!(f>>charge[i])) throw 1;
        if (!(f>>deliver[i])) throw 1;
    }

    string type, name;
    int battery;
    while (!f.eof()) {
        cout << " a ";
        if (f>>type && f>>name && f>>battery) {
            if (type=="Mac") {
                Mac r = Mac(name,battery);
                robots.push_back(&r);
            };
            if (type=="Eco") {
                Eco r = Eco(name,battery);
                robots.push_back(&r);
            };
            if (type=="Pro") {
                Pro r = Pro(name,battery);
                robots.push_back(&r);
            };
        };
    };
}

It seems the problem occurs in the while loop. If I want to read from a 3 row long text, I get 4 letter a-s on the screen (I have the program print one before reading every row).

Is f.eof() not the function I need to use here?

Community
  • 1
  • 1
Andesz
  • 89
  • 1
  • 4

2 Answers2

1

This is one of the most common problems with reading from files. Checking f.eof() will only tell if you the previous read hit the end of the file. Hence, after the last successful read (where you got your third "a" printed), eof() returns false and your loop executes one more time, outputting an extra "a".

Instead, use your extraction line as the condition for your while loop:

while (f>>type && f>>name && f>>battery) {
    if (type=="Mac") {
        Mac r = Mac(name,battery);
        robots.push_back(&r);
    }
    if (type=="Eco") {
        Eco r = Eco(name,battery);
        robots.push_back(&r);
    }
    if (type=="Pro") {
        Pro r = Pro(name,battery);
        robots.push_back(&r);
    }
}

This works because as soon as one of your extractions hits the end of the file, the while condition will be false and the loop won't execute.

If you want to continue after badly formatted lines, I recommend that you use std::getline instead:

std::string line;
while (std::getline(f, line)) {
  std::stringstream ss(line);
  if (ss >> type && ss >> name && ss >> battery) {
    // ...
  }
}

The reason for using this std::getline approach is because you would have had a problem if half of a line had been correctly formatted. Your approach would have read in perhaps type and name then failed on battery and the next iteration of the loop would have started from the same place.

You're also going to have a problem with the fact you're pushing pointers to objects that have automatic storage duration into some vectors. When the block in which the objects are created ends, the pointers will be pointing to an invalid object.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • thank you :) but wont this result in the program quitting the loop if it finds a "wrong" line? i would want to read in all lines given in a correct form – Andesz Dec 20 '12 at 14:16
  • The function `f.eof()` may or may not return `true` if the previous input succeeded. It's only useful after you know that an input has failed; if it returns `true`, there's a good chance that the previous input failed because of end of file (but even that is not guaranteed). – James Kanze Dec 20 '12 at 14:43
0

This is a FAQ. In C/C++, the end-of-file condition is triggered only after you have tried to read past the end. So, you can't assume from feof() == false that input is available (because you could be exactly at the end of the file, but not yet past it). You should always test for valid input after a read operation.

arayq2
  • 2,502
  • 17
  • 21