I'm currently trying to write a while loop that checks if the text file has read all the contents inside. I've tried using
while(!in.eof())
but as usual it executes my loop an extra iteration, printing my last output twice. I am reading my data in from a method inside a class, so I cannot use getline as my while test to check if the file has read input or not. Is there any way to force my loop to check if the end of file has been read before the eof() test is executed?
Don't believe that would solve my problem either as I'm reading my data using a read function inside of my class Rational. Here pieces of my code related to my issue.
Rational op1, op2, res; // objects of class Rational
char oper;
//.
//.
//.
while(!in.eof()) // <---- Problem is this, causing my last output to print twice
{
op1.read(in); // read in first rational
in >> oper; // read in the operation to be performed
op2.read(in); // read in second rational
switch(oper) // checks which operation to call depending on oper
{
case'+' : res = op1.add(op2);
break;
case'-' : res = op1.subtract(op2);
break;
case'*' : res = op1.multiply(op2);
break;
case'/' : res = op1.divide(op2);
break;
default: out << "No operator was found." << endl;
}
res.gcd(); // find greatest common divisor of result rational
op1.print(out); // print first rational number
out << " " << oper << " "; // print operator used
op2.print(out); // print second rational number
out << " = ";
res.print(out); // print resulting rational number
out << endl;
}
//.
//.
//.
void Rational::read(ifstream& in)
{
char d;
in >> d >> num >> d >> denom >> d;
if( denom == 0 ) // if rational denom read in is 0 print error and set to 0 / 1
{
cout << "Error ( " << num << " / " << denom << " ) not a legal value."
<< " Rational changed to ( 0 / 1 )." << endl;
num = 0;
denom = 1;
}
}
For this assignment I'm not allowed to use overloaded operators. My next assignment will be changing various parts of this program to use overloaded operators though.
I guess you could modify your Rational::read function slightly so that it returns true or false depending on whether the input succeeded.
Then it would just be a matter of doing
6 7 8
while (op1.read(in) && in >> oper && op2.read(in))
{
// ...
Alternatively, without changing Rational::read at all, you could try any one of these:
6 7 8 9 10 11 12 13
while (true)
{
op1.read(in);
in >> oper;
op2.read(in);
if (in.eof()) // Might be better to make it just 'if (!in)', but whatever...
break;
// ...
6 7 8
while ( (op1.read(in), in) && in >> oper && (op2.read(in), in) )
{
// ...
EDIT: whoops, extra semicolon, good catch @Valandu
and it worked out, I had to remove the semicolon after in >> oper cause of a compiler error. But I'm not sure how it works in terms of how the following work.
(op1.read(in),in)
or
(op2.read(in), in)
What does the comma operator after op1.read(in) do exactly? Does it check if there are contents in the file or if the file is still open? If you could explain this to me that would be awesome.
in >> oper
Makes sense to me because it checks if there is a character read into oper. Thank you for your help.
The comma there basically turns two expressions into one expression, and AFAIK it returns the second one. Its being used here to first execute the read in and then returns the value of 'in' (true or false).