Not getting all lines from a text file when using getline() in C++
Asked Answered
E

2

0

I was given a homework assignment to generate a txt file containing a random number of lines, each with a random amount of integers, ranging between a minimum value and a maximum value. Lots of rand() fun.

In any case, that was the easy part. The second part of the problem is to read over the first file and create a second file that contains some statistics, such as: the sum of all integers in the file, their average, min and max values, and my main issue: the sum of all integers in each line.

I have written the following code:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <cmath>
using namespace std;

int main()
{
        string newLine;
        stringstream ss;
        int newInput = 0, oldInput = 0;
        int lineSum = 0;
        int lineCounter = 0;
        int allSum = 0;
        int intCounter = 0;
        double averageOfAll = 0;
        int minInt = 0;
        int maxInt = 0;

.... // generating the first file. No issues here.

ifstream readFile;
readFile.open("inputFile.txt");

ofstream statFile;
statFile.open("stat.txt");

if(readFile.is_open()) {
        while (getline(readFile, newLine)) {    //my problem should be somewhere
                                                //around here...  
                ss.str("");
                ss << newLine;
                while(!ss.eof()) {
                        oldInput = newInput;
                        ss >> newInput;

                        cout << newInput << endl;
                        lineSum += newInput;
                        allSum += newInput;
                        intCounter++;
                        minInt = min(oldInput, newInput);
                        maxInt = max(oldInput, newInput);
                }

                lineCounter++;
                statFile << "The sum of all integers in line " << lineCounter
                << " is: " << lineSum << endl;
                lineSum = 0;
        }

        readFile.close();

        averageOfAll = static_cast<double>(allSum)/intCounter;

        statFile << endl << endl << "The sum of all integers in the whole file: "
        << allSum;
        statFile << endl << "The average of value of the whole stream of numbers: "
        << averageOfAll;
        statFile << endl << "The minimum integer in the input file: "
        << minInt;
        statFile << endl << "The maximum integer in the input file: "
        << maxInt;
        statFile << endl << endl << "End of file\n";

} else
        cout << endl << "ERROR: Unable to open file.\n";

statFile.close();

return 0;
}

When running the program, it seems like my loops do iterate over all the lines in the file. However, they only collect the integers from the first line, and the rest remains 0.

I would post screenshots of my outputs, but I do not have enough rep :( can anyone help out?


It worked!

inputFile.txt ^ inputFile.txt

statFile.txt

statFile.txt (my output) ^

And like P0W and James Kanze suggested, it was a flag issue and a misuse of my streamstring. I corrected my code as follows:

.
.
.
 while (getline(readFile, newLine)) {
                    stringstream ss(newLine);

                    while(ss >> newInput) {

                            lineSum += newInput;
                            allSum += newInput;
                            intCounter++;
                            minInt = min(minInt, newInput);
                            maxInt = max(maxInt, newInput);
                    }
.
.
.

Thank you all!

Epicurus answered 1/10, 2014 at 4:17 Comment(2)
You might add c++ to the subject list. A lot people probably don't follow the more precise labels (or even know that they exist).Slash
Just did, JGrice suggested an edit that I accepted :) Thank you allEpicurus
S
1

There are several issues, but the main one is that you're trying to reuse ss (which should properly be an std::istringstream). It's possible to do so, but it's fairly difficult to get right, since streams hold a lot of state which needs reinitializing. (In this case, the stream memorizes that it has seen end of file, and doesn't do anything else until that has been reset.) Your loop should look like:

while ( getline( readFile, newLine ) ) {
    std::istringstream ss( newLine );
    //  ...
}

And once you've got the std::istringstream, you don't want to loop until eof (which may or may not be set after the last successful input); you want to loop until an input fails. (After the input fails, you may want to check eof: if it isn't set, the input failed because of a format error in the line; e.g. someone entered "abc" instead of an integer.)

Slash answered 3/10, 2014 at 16:8 Comment(0)
D
1

You can try following for your inner while loop

ss << newLine;

while( ss >> newInput ) 
{
  //.... Your logic,
 // might need little update

  oldInput = newInput;
}

ss.clear( ); // clear the flags !
Dmitri answered 3/10, 2014 at 16:3 Comment(2)
Oh, so it might be a flag issue? because it was not cleared for the next iteration??Epicurus
@GilDekel It's almost certainly a flag issue, but a stream has a lot more flags than you'd imagine, and clear() only resets the error flags. Unless you really know what you're doing, and have a performance problem, don't try to reuse a stream; just create a new one.Slash
S
1

There are several issues, but the main one is that you're trying to reuse ss (which should properly be an std::istringstream). It's possible to do so, but it's fairly difficult to get right, since streams hold a lot of state which needs reinitializing. (In this case, the stream memorizes that it has seen end of file, and doesn't do anything else until that has been reset.) Your loop should look like:

while ( getline( readFile, newLine ) ) {
    std::istringstream ss( newLine );
    //  ...
}

And once you've got the std::istringstream, you don't want to loop until eof (which may or may not be set after the last successful input); you want to loop until an input fails. (After the input fails, you may want to check eof: if it isn't set, the input failed because of a format error in the line; e.g. someone entered "abc" instead of an integer.)

Slash answered 3/10, 2014 at 16:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.