-2

I'm attempting to read data from an input file using a loop that should stop at the end of the file within a function. The data in the file is arranged in lines like this:

 Zip Drive
 89
 Warehouse C
 75.89
 Keyboard
 133
 Warehouse C
 25.95

On the fourth line the variable is filled with some garbage input and everything read after is blank. The loop also will not end.

int ReadData(string productName[], string productLocation[], int productQty[], double productPrice[])
{
    ifstream infile;
    int i = 0;
    infile.open("prog1.txt");

    do {
        getline(infile, productName[i]);
        infile >> productQty[i];
        getline(infile, productLocation[i]);
        infile >> productPrice[i];
        i++;
    } while (!infile.eof());

    infile.close();
    return i;
} 
Derek
  • 1
  • 1
  • 1
    Possible duplicate of [Why is iostream::eof inside a loop condition considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – Barmar Jan 19 '18 at 23:20
  • Also see https://stackoverflow.com/questions/10553597/cin-and-getline-skipping-input – Barmar Jan 19 '18 at 23:21
  • 1
    You were referred to those questions in your [previous question](https://stackoverflow.com/questions/48349551/using-getline-while-reading-an-input-file) – Barmar Jan 19 '18 at 23:22
  • If the file reading fails for some reason other than end of file, How do you expect the loop to stop? Handy reading: https://stackoverflow.com/a/7868998/4581301 See if you can take advantage of option 2. – user4581301 Jan 19 '18 at 23:36
  • I already addressed that it is in the guidelines of my assignment to use eof as the loop condition and I also edited to explain that I tried .ignore() and it worked for my issue with productLocation but not productPrice. – Derek Jan 19 '18 at 23:42
  • You cannot use eof for this and have robust, working code. Have a chat with your instructor to clear this up, because either they are mistaken or you are. Sadly I wouldn't be overly surprised if the instructor is mistaken and has mislead you. – user4581301 Jan 19 '18 at 23:48

1 Answers1

1

The infile >> productQty[i] and infile >> productPrice[i] statements are reading int/double values and leaving the line breaks after them in the stream, to be read by the next std::getline() call, which is not what you want to happen.

You need to either:

  1. use std::getline() to read every line, and then use std::istringstream to parse the int/double values from their respective lines:

    int ReadData(string productName[], string productLocation[], int productQty[], double productPrice[])
    {
        ifstream infile("prog1.txt");
        int i = 0;
    
        while (getline(infile, productName[i]))
        {
            getline(infile, line);
            istringstream(line) >> productQty[i];
            getline(infile, productLocation[i]);
            getline(infile, line);
            istringstream(line) >> productPrice[i];
            ++i;
        }
    
        infile.close();
        return i;
    }
    
  2. call infile.ignore() after reading the int/double values, to read and dismiss the line breaks:

    int ReadData(string productName[], string productLocation[], int productQty[], double productPrice[])
    {
        ifstream infile("prog1.txt");
        int i = 0;
    
        while (getline(infile, productName[i]))
        {
            infile >> productQty[i];
            infile.ignore(numeric_limits<streamsize>::max(), '\n');
            getline(infile, productLocation[i]);
            infile >> productPrice[i];
            infile.ignore(numeric_limits<streamsize>::max(), '\n');
            ++i;
        }
    
        infile.close();
        return i;
    }
    

In either case, the arrays must be pre-allocated with enough elements to hold as many products as are in the file. Since the code has no way of actually verifying that count, I would suggest an alternative safer approach:

struct productInfo
{
    string name;
    string location;
    int quantity;
    double price;
};

istream& operator>>(istream &in, productInfo &out)
{
    string line;

    if (!getline(in, out.name)) {
        // don't set failbit yet, in case this is just EOF...
        return in;
    }

    // at this point, a new product is encountered, so
    // any missing data is considered a failure...

    if (!getline(in, line)) {
        in.setstate(failbit);
        return in;
    }

    if (!(istringstream(line) >> out.quantity)) {
        in.setstate(failbit);
        return in;
    }

    if (!getline(in, out.location)) {
        in.setstate(failbit);
        return in;
    }

    if (!getline(in, line)) {
        in.setstate(failbit);
        return in;
    }

    if (!(istringstream(line) >> out.price)) {
        in.setstate(failbit);
        return in;
    }

    return in;
}

int ReadData(vector<productInfo> &products)
{
    ifstream infile("prog1.txt");
    int i = 0;

    productInfo info;
    while (infile >> info)
    {
        products.push_back(info);
        ++i;
    }

    infile.close();
    return i;
}
Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620