-2

I've read and tried the suggestions made on this forum and others. They all sound like they should sove this problem, but it persists. I'm a tutor and trying to help a student. I know i must be missing something: Here is my code:

    /* data in file
2 5
12 76
1x  87
17 4
*/

    while (fin >> n1 >> n2)     
    {
        bool failed = fin.fail();
        if (!failed )
        {
            total = n1 + n2;
            grandTotal += total;
            cout << n1 << " + " << n2 << " = " << total << endl;
        }
        else
        {
            cout << "Error in line: " << endl;
            fin.clear();
            fin.ignore(std::numeric_limits<streamsize>::max(), '\n');
        }
            
    }

When it encounter the third line of data, it displays "error in line" but then it doesn't read any further, it just drops out of the read loop as though it has reached end of file.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
RonD
  • 9
  • 1
  • Sorry is it `2 5 12 76 1x 87 17 4` that's in the file? I think the formatting is a little off there. – WBuck Oct 15 '21 at 01:53
  • 4
    The `while` condition is set to `false` when it encounters `1x` (which isn't an `int`), hence the loop exits as the condition is no longer `true`. – WBuck Oct 15 '21 at 01:57
  • 1
    You might consider reading the data into a `std::string` using `std::getline` and then parsing that string using a `std::stringstream`. – Retired Ninja Oct 15 '21 at 02:00
  • 2
    Please provide a [mre], `fin.fail()` can never be true as the while loop condition would be false if it was. So I can't see how the error statement would be printed – Alan Birtles Oct 15 '21 at 06:28
  • 1
    can't reproduce https://godbolt.org/z/5adxv56j8 – Alan Birtles Oct 15 '21 at 07:18
  • 1
    If you remove the part about displaying "error in line" from your problem description, then your result would be reproducible. *The code you presented encounters the third line of data, but doesn't read any further; it just drops out of the read loop as though it had reached the end of the file.* This might seem like a small detail, but it is enough to indicate that we are not looking at the right code snippet, that solutions based on the code we see might be inapplicable to your real code. – JaMiT Oct 16 '21 at 05:30
  • How are you going to tell whether `fail` was set by erroneous data or by hitting the end of file? – zkoza Oct 16 '21 at 06:35

1 Answers1

1

The problem is that the following loop:

while (fin >> n1 >> n2)

exits on operator>> failing, i. e. the loop body is not entered any more and you don't get the chance to recover.

To solve, you might prefer checking within the loop:

for(;;)     
{
    if(fin >> n1 >> n2)
    {
        // OK ...
    }
    // we need to distinguish end of file from other failures!
    else if(fin.eof())
    {
        break;
    }
    else
    {
        // error
    }
}

Alternatively one could read into a std::string via std::getline and parse this one:

std::string s;
while(std::getline(fin, s))     
{
    std::istringstream sin(s);
    if(fin >> n1 >> n2)
    {
        // OK ...
    }
    else
    {
        // error ...
    }
}

The former is a bit more efficient, the latter is a bit more handy.

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • 2
    *"i. e. the loop body is not entered any more and you don't get the chance to recover."* -- in addition to not recovering, you don't get the `Error in line: ` message, right? Contrary to what is claimed in the question? – JaMiT Oct 15 '21 at 03:43
  • @JaMiT Good point, that line *cannot* be met either. Fail bit is set after input operations, which occurs in the while condition. If we enter the body, it hasn't been set yet, but then there's no other input operation that might set it… – Aconcagua Oct 15 '21 at 04:02
  • The answer given above worked! I thn modified it a bit to avoid using a break to: while(!eof) { if (fin >> n1 >> n2) { total = n1 + n2; grandTotal += total; cout << n1 << " + " << n2 << " = " << total << endl; } // we need to distinguish end of file from other failures! else if (fin.eof()) { //break; eof = true; } else { cout << "Error in line: " << endl; fin.clear(); fin.ignore(std::numeric_limits::max(), '\n'); } } cout << "Running total = " << grandTotal << endl; – RonD Oct 18 '21 at 01:22
  • @RonD That modification is [wrong](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong), though (see link; this is a C question, but *exactly* the same applies for C++ streams, too). What you *could* do, though, would be the following: `while(fin >> n1 >> n2, !fin.feof()) { if(fin){ /*OK*/ } else { /*error*/ } }`. – Aconcagua Oct 18 '21 at 09:07
  • @RonD Side note: Have you considered what happens if there's an odd number of numbers on one line? All subsequent lines would be splitted then until another odd line occurs: `1 2 3 \n 4 5 \n 6` would accept pairs (1, 2), (3, 4), (5, 6). If that's an issue you might prefer the `std::getline` variant, which covers that (discarding `1, 2, 3` entirely or accept it as (1, 2), depending on your needs; accepting (4,5); discarding `6`). – Aconcagua Oct 18 '21 at 09:19