Miladdarren Miladdarren - 3 years ago 228
C++ Question

Fixing infinite loop

I have a code that takes 2 numbers from user and check if the input is equal or more than 0 and also checks if the input is numeric.

Everything is fine until I test the code with a non numeric value like "Hi".

By doing this the program goes into an infinite loop.

I want the code request another input if the user entered bad input but it goes into a nonstop loop.

Here is the code:

#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>
using namespace std;

class Exp:public runtime_error
{
public:
Exp(): runtime_error("input must be a numeric value equal or more than 0!\n")
{
}
};

class GradeBook
{
private:
float number1,number2;
public:
GradeBook(float n1, float n2) : number1(n1), number2(n2)
{
}
void setnumber1(float num1, int re1)
{
if(num1 >= 0 && re1)
number1 = num1;
else
throw (Exp());
}
float getnumber1()
{
return number1;
}
void setnumber2(float num2, int re2)
{
if(num2 >= 0 && re2)
number2 = num2;
else
throw (Exp());
}
float getnumber2()
{
return number2;
}
};

int main()
{
int result1, result2;
float num1 = 0, num2 = 0;
GradeBook myGradeBook(0, 0);

reNum1:
printf("Please enter number 1:\n");
result1 = scanf("%f", &num1);
try{
myGradeBook.setnumber1(num1, result1);
}
catch(Exp exp)
{
cout<<exp.what();
goto reNum1;
}

reNum2:
printf("Please enter number 2:\n");
result2 = scanf("%f", &num2);
try{
myGradeBook.setnumber2(num2, result2);
}
catch(Exp exp)
{
cout<<exp.what();
goto reNum2;
}
return 0;
}

Answer Source

You problem happens because of scanf behaviour. When calling scanf("%f") it will try to read a float from stdin. When user enters Hi, there is no float to read so scanf will read nothing and return 0(the number of format specifiers filled with data read from stdin). The issue is that the input still has unread string Hi pending, so the next call to scanf("%f"), will repeat exactly the same operation. What you need to do is to "clear" stdin, so that user can enter new input. This may be done ie. by calling getline on failure:

    try{
        myGradeBook.setnumber1(num1, result1);
    }
    catch(Exp exp)
    {
        string tmp;
        getline(cin, tmp);
        cout<<exp.what();
        goto reNum1;
    }

Please note, that mixing C-style IO(scanf/printf) and C++ style IO(cout/cin) may have a performance penalty.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download