Program that checks if a user inputted double variable is valid breaks when it's not valid. How do I fix it?

I'm working on a project for my C++ course and part of it is to make sure there is no way the user can break the program by entering in bad information.

The program is simple, the user enters a dollar amount, then selects a currency type (by entering an A-I), then it converts the amount and displays it. Then prompts the user if they want to do it again.

Here's the part of the program that checks if it's valid:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
double getDollarAmt()
{
	double dollarAmount;

	while (1) {
		cout << "Please enter the total dollar amount to exchange: ";
		cin >> dollarAmount;

		if (!cin.fail()) {
			break;
		} else {
			cout << "Error. Please enter a valid number.\n";
			continue;
		}
	}

	return dollarAmount;
}


I've tried a hundred different ways, every time it works fine when the user enters a number, but when they enter a wrong number, it displays the error constantly filling up the entire screen.

How do I prevent it from displaying the error a thousand times over? It's been bothering me for hours now, I can't figure out what's wrong.

Don't know if it's the best method to do this but

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
double getDollarAmt()
{
	double dollarAmount;
	
	while (1) {
		cout << "Please enter the total dollar amount to exchange: ";
		cin >> dollarAmount;
		
		if (!cin.fail()) {
			break;
		} else {
			while (cin.get()!='\n')
				cin.clear();
			cout << "Error. Please enter a valid number.\n";
			continue;
		}
	}
	
	return dollarAmount;
}


seems to be working
Last edited on
That works quite nicely. I'm just a starting out student, so I don't want to just take code without learning/understanding it, can you explain this part a bit?
1
2
while (cin.get()!='\n')
	cin.clear();

Basically if what the user inputs is not an enter, it clears it?

I've also found that if you enter garbage, but if the first character (or the first character after a space) is a number, it grabs onto that number and continues, and the rest of what's after it goes onto the next inputs breaking the program a bit.

But generally, that'll be enough for this project. I'll figure out all the "how to prevent the user from breaking your program" failsafes later.

Thanks!
You can also do this
1
2
cin.clear();
while (cin.get()!='\n')continue;

so that it doesn't grab onto numbers after space.

Anyways, cin.clear() resets input. Then while (cin.get()!= '\n')continue; is used to read the remaining input through the end of the line, getting rid of bad input on that line.
Ah alright, that makes sense. And it basically fixed it, except if the first input is a number, then garbage follows, it still breaks it. Putting the same code outside of the while loop right before the return fixes it. What that ends up doing is accepting the first number as an input, then ignores any bit of garage that follows.

Any way to make that count as an error, too? So the only thing it'll accept is a number and just a number?

Also, is:
1
2
cin.clear();
while (cin.get()!='\n')continue;

Just a simplified version of:
1
2
3
4
5
while (cin.get()!='\n')
{
	cin.clear();
	continue;
}
?
Because I've found the latter works the same, and looks more familiar to me (due to the way I've been learning it).
The canonical way to do that is:

1
2
3
4
5
6
#include <limits>

// ...

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


Clearing the error flag (cin.clear()) isn't necessary after every cin.get, and the continue isn't necessary at all.

However the only way to really accomplish the level of error checking you're looking for is to read the input in as a string and parse it to make sure it fits the format of the data you're looking for. For instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <sstream>
#include <string>
#include <cctype>

bool isValidDollarAmount(std::string & s)
{
    // skip any whitespace:
    unsigned index = 0 ;
    while ( index < s.length() && std::isspace(s[index]) )
        ++index ;

    bool decimalEncountered = false ;

    if ( s[index] == '$' || std::isdigit(s[index]) || s[index] == '.' )
    {
        if ( s[index] == '$' )
        {
            if ( index+1 >= s.length() )
                return false ;
            
            s[index] = ' ' ;  // remove the $ so the conversion won't fail.
        }   

        if ( s[index++] == '.' )
        {
            if (index >= s.length() )
                return false ;
            decimalEncountered = true ;
        }

        while ( index < s.length() )
        {
            if ( !std::isdigit(s[index]) )
            {
                if ( !s[index] == '.' || decimalEncountered )
                    return false ;

                decimalEncountered = true ;
            }

            ++index ;
        }

        return true ;
    }
    return false ;
}

double getDollarAmt()
{
    std::string input ;

    do
    {
        std::cout << "Please enter the total dollar amount to exchange: " ;
        std::getline(std::cin, input) ;
    } while ( !isValidDollarAmount(input) && (std::cout << "Error.  Please enter a valid number.\n")) ;

    std::istringstream is(input) ;
    double dollarAmount;
    is >> dollarAmount ;
    return dollarAmount ;
}
Topic archived. No new replies allowed.