tags:

views:

148

answers:

2

The bug starts at cin.getline ( string, 25, '\n' ); or the line below it (strtod). If I use cin, it works, except I cannot quit out. If I type anything that's not a double, an infinite loop runs. Need help. Basically, the first iteration runs, does not ask for input, so the user gets the math questions wrong. The second iteration works fine. And the next is fine, too. If I back out, using q, I get dumped back to the mode-chooser. After choosing a mode, the bug reappears for the first iteration. Next iterations it's gone.

int main()
{
    char choice, name[25], string[25], op;
    int operator_number, average, difference, first_operand, second_operand, input, answer, total_questions = 0, total_correct = 0;
    double dfirst_operand, dsecond_operand, dinput, danswer, percentage;
    bool rounding = false;

    srand ( time(NULL) );

    cout << "What's your name?\n";
    cin.getline ( name, 25, '\n' );
    cout << '\n' << "Hi, " << name << ".";

    do {
    do {
    cout << "\nWhich math operations do you want to practice?\n  1. Addition\n  2. Subtraction\n  3. Multiplication\n  4. Division\n  5. Mixed\n  6. Difference of squares multiplication.\nChoose a number (q to quit).\n";
    cin >> choice;
    } while( choice < '1' || choice > '6' && choice!= 'q');

    cout << "\n";

    switch(choice) {
    case '1':
            while( string[0]!= 'q') {
                dfirst_operand = rand() % 15 + 1;
                dsecond_operand = rand() % 15 + 1;
                danswer = dfirst_operand + dsecond_operand;
                cout << dfirst_operand << " + " << dsecond_operand << " equals?\nEnter q to quit.\n";
                cin.getline ( string, 25, '\n' );
                dinput = strtod( string,NULL);
                //cin >> dinput;
                if(string[0]!='q') {
                ++total_questions;
                if(dinput==danswer) {
                    ++total_correct;
                    cout << "Correct. " << total_correct << " correct out of " << total_questions << ".";
                } else {
                    cout << "Wrong. " << dfirst_operand << " + " << dsecond_operand << " equals " << danswer << ".\n" << total_correct << " correct out of " << total_questions << ".";
                };
                percentage = floor(10000 * (float) total_correct / total_questions)/100;
                cout << ' ' << percentage << "%.\n\n";
                }
            }
            break;
            }
    } while(choice!='q');
    return 0;
}
A: 

Try to throw a cin.ignore() right after or before the cin.getline().

JonH
Thanks for your answer. It fixed that bug, but it creates another one. I added cin.ignore(); after cin.getline ( string, 25, '\n'); and now it won't register correct answers. Could you explain what cin.ignore does? I've read a bit about it, but I'm still confused as to what it does.
Duc
Down-voted because it is just incorrect (even with Changeling's edit), and reads like a 'guess'. Don't *try*; do.
Clifford
@Clifford - It is not a guess, you can still use cin.ignore(). -1 to you because your post is JUST A GUESS
JonH
You said "Try"; that's why it sounded like a guess. Calling ignore *after* which is what you originally wrote would not solve this problem. Change it to just *before* and it would be reasonable.
Clifford
+1  A: 

The problem is this line:

 cin >> choice;

This line parses the input buffer for character input that can be converted to an integer. So if you enter:

2<newline>

The string "2" is converted, and <newline> remains in the input buffer; so the subsequent cin.getline() is satisfied immediately.

This is also why JonH's suggestion does not work, you need to purge the input buffer after the cin << choice input. An alternative is to use cin.getline() for all input (or better; use ::getline() which operates on std::string rather than C-strings), and then parse that input using a std::istringstream object when you need formatted input scanning.

However if you must use cin.ignore() to solve this problem, you should do it thus:

cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' ) ;

where std::numeric_limits is defined in the header. Your solution trusts the user not to enter more than 25 characters. That is not a very safe assumption.

Clifford
I used your method and it's perfect. It's very safe to use and it works fine. Thanks.
Duc