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
  • 242,098
  • 41
  • 402
  • 602

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
  • 505,946
  • 29
  • 409
  • 696