0

I am writing a program that reads in data from a file. The file contains lines of integers, such as

5 6 2 8 6 7

2 5 3

4 0 9 1 3

The first integer of each line corresponds to how many numbers there are in that line. My goal is to read in each line, store the numbers in a vector, and do some operation on them. Here is what I have done:

int main(){

 vector<int> vec;
 int amount;
 int nums;
 ifstream file ("file.txt");


 while(!(file.eof())){
     file >> amount;
     cout << amount << endl;

     for (int i = 0; i < amount; i++){
         file >> nums;
         vec.push_back(nums);
     }

 printArray(vec);
 bubbleSort(vec);
 vec.clear();
 }

 return 0;
}

Unfortunately, the last line always gets read twice. I looked online and saw that the eof() function should not be used to maintain loops. What else could I use in this situation?

Thanks.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
user545642
  • 91
  • 1
  • 14
  • Maybe `while(file >> amount){` – 001 Jan 16 '20 at 00:21
  • Didn't the places that say not to use `eof()` show what you should do instead, like the question I linked to? – Barmar Jan 16 '20 at 00:22
  • Unfortunately, I tried fgets() but that didn't work. I'm completely stumped. I'm using c++ and vectors, and am a beginner. Couldn't understand that code. – user545642 Jan 16 '20 at 00:30
  • 1
    [Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/) – Remy Lebeau Jan 16 '20 at 01:42

1 Answers1

1

operator>> sets the stream's eofbit flag if it tries to read past EOF. You can use that condition to break your loops. But you have to actually perform a read operation BEFORE you can evaluate eof(). See Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong? for more details on that.

Since you are dealing with line-based text, you can use std::getline() to read each line first, and then you can use std::istringstream to parse each line, eg:

int main()
{
    vector<int> vec;
    ifstream file ("file.txt");
    string line;

    while (getline(file, line)) {
        istringstream iss(line);
        int amount, nums;

        iss >> amount;
        cout << amount << endl;

        for (int i = 0; (i < amount) && (iss >> nums); ++i){
            vec.push_back(nums);
        }

        printArray(vec);
        bubbleSort(vec);
        vec.clear();
    }

    return 0;
}

Alternatively, you can simply take advantage of the fact that operator>> skips whitespace, including line breaks, eg:

int main()
{
    vector<int> vec;
    int amount, nums;
    ifstream file ("file.txt");

    while (file >> amount) {
        cout << amount << endl;

        for (int i = 0; (i < amount) && (file >> nums); ++i){
            vec.push_back(nums);
        }

        printArray(vec);
        bubbleSort(vec);
        vec.clear();
    }

    return 0;
}

Although, this approach would be a little less resilient to errors in the input data, compared to the std:getline() approach. If the actual amount of numbers in a given line does not match the specified amount at the beginning of the line, this approach will get its reading of the file out of sync. Worse, if a given line contains any non-integer values, this approach will fail to read any subsequent data at all.

In the std:getline() approach, if a given line is malformed, the code will simply move on to the next line and continue on like nothing bad happened.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770