0

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;
}
4

2 回答 2

1

我不知道抛出的异常是什么,所以我只是添加了一些 if 语句来防止由于空文件或不存在文件而导致的任何错误。在问题引起问题之前处理问题的根源可能会更好。(我真的不太了解异常。)

这是我在 main.cpp 中的新代码

if ( argc > 1 ) //a filename is present
{
    try
    {

        tapeInputStream.exceptions( tapeInputStream.failbit );

        if ( existFile( argv[1] ) ) //no need to read file if it does not exist
        {
            tapeInputStream.open( argv[1], ios_base::in );

            if ( emptyFile() ) //no need to read file if it is empty
            {
                tapeInputStream.close();
            }
        }
    }
    catch ( ios_base::failure &ioError )
    {
        ErrorHandling::handleInputStreamError( tapeInputStream, ioError );
    }
}
于 2013-04-12T12:19:16.623 回答
0

在行catch ( ios_base::failure &ioError )中,您只是在处理一种类型的错误。尝试catch(...)所有错误。请提及运行代码后出现的其他错误。

另外请确保您以正确的方式提供论据。 Executable<space>file_name_as_argument.

于 2013-04-11T14:05:01.740 回答