I am reading Jesse Liberty's SAMS Teach Yourself C++ in 10 Minutes and testing the examples in the book. I find that there are some bugs in the code about file i/o but I don't know where they are. The book does not mention anything about them. I think the problem is caused by fstream
and catch(...)
but I don't know how to fix it. So I would like to seek help from experienced C++ users here to help me.
Problems:
I don't know why the program always call ErrorHandling::handleNotANumberError();
when the input file is empty.
Moreover, the program has more errors when the input file does not exist. Exceptions are caught and basic_ios::clear
is read. Why are there errors?
When I delete the codes about exceptions, it can work well when the file does not exist.
And when I input from an empty file, the message "invalid operator" is present.
I think that invalid operator is the eof character. Is it?
I have searched in Google but still cannot figure out what is happening. I know the following code is a bit long but I really want to know what happens.
The major content in main.cpp :
ifstream tapeInputStream; //global variable for callback
char getOperator()
{
char operatorInput;
if
(
tapeInputStream.is_open() &&
( !tapeInputStream.eof() )
)
{
tapeInputStream >> operatorInput;
}
else
{
cin >> operatorInput;
}
return operatorInput;
}
float getOperand()
{
float operandInput = 1;
if
(
tapeInputStream.is_open() &&
( !tapeInputStream.eof() )
)
{
tapeInputStream >> operandInput;
}
else
{
cin >> operandInput;
}
return operandInput;
}
void showResult( float theResult )
{
cout << endl << "Result: " << theResult << endl;
}
int main( int argc, char* argv[] )
{
if ( argc > 1 ) //a filename is present
{
try
{
tapeInputStream.exceptions( tapeInputStream.failbit ); //cin or ofstream?
tapeInputStream.open( argv[1], ios_base::in );
}
catch ( ios_base::failure &ioError )
{
ErrorHandling::handleInputStreamError( tapeInputStream, ioError );
//the stream will be unopened but the failbit will not be set
}
}
Calculator::aCalculatorExternalInterface CalculatorExternalInterface;
CalculatorExternalInterface.getAnOperator = getOperator;
CalculatorExternalInterface.getAnOperand = getOperand;
CalculatorExternalInterface.showResult = showResult;
int result = Calculator::calculateFromInput( CalculatorExternalInterface );
tapeInputStream.close(); //close the file to make output stream in tape() possible
Calculator::tape( '.', 0, argv[1] ); //stream and delete the tape
return result;
}
Part of namespace Calculator in ExternalInterfaceModule.cpp :
bool nextCalculation
(
const aCalculatorExternalInterface &theCalculatorExternalInterface
)
{
char operatorInput = theCalculatorExternalInterface.getAnOperator();
switch ( operatorInput )
{
case '.': //stop
return true; //done will become true
case '?': //show the tape
tape( operatorInput );
return false;
case '=': case '@': //no operand sent to accumulator
{
anOperator operatorValue =
( operatorInput == '=' ? query : reset );
float result = accumulator( operatorValue );
if ( operatorValue == query )
{
theCalculatorExternalInterface.showResult( result );
}
return false;
} //use curly brackets to define the scope
case '+': case '-': case '*': case '/': //calculation
{
float number = theCalculatorExternalInterface.getAnOperand();
anOperator operatorValue =
operatorInput == '+' ? add :
operatorInput == '-' ? subtract :
operatorInput == '*' ? multiply :
divide;
accumulator( operatorValue, number );
tape( operatorInput, number );
return false;
}
case '!': //self-test
selfTest();
return false;
default: //anythings else is an error
throw runtime_error( "Error: Invalid operator.");
}
}
int calculateFromInput
(
aCalculatorExternalInterface &theCalculatorExternalInterface
)
{
ErrorHandling::initialise();
bool done = false;
do
{
try
{
done = nextCalculation( theCalculatorExternalInterface );
}
catch ( runtime_error runtimeError )
{
ErrorHandling::handleRuntimeError( runtimeError );
}
catch (...)
{
ErrorHandling::handleNotANumberError();
}
}
while ( !done ); //continue when undone
return 0;
}