简体   繁体   中英

Input limitation and error checking in C++

I have an issue with the following C++ program. It calculates and prints out the blood alcohol concentration using the Widmark formula based on information the user enters. There is some input error checking, for example if a random character is entered after being asked for which beverage they drank, or if any number higher than 400 is entered after being asked for weight. Then an error message appears (which is intentional) and the user is asked for input again.

However, they are some issues with the input error checking , for example if x>1 characters are entered after being asked for the gender, the error message appears x times (it should appear only once). If any non-integer characters are entered after being asked for weight, the error message appears infinite times, resulting in an endless loop (same issue with litres drunk after entering non-float values).

Is there some way to limit the inputs so that error messages only appear once after any invalid input?

#include<iostream> // for std::cin and std::cout
#include<iomanip> // for std::fixed and std::setprecision

float BAC (char gender, int weight, char drink, float litres) // function to calculate blood alcohol concentration
{
    // local variables
    float bac, rate, vol; // blood alcohol concentration, widmark rate, volume percentage

    // determine widmark rate
    if (gender == 'm' || gender == 'M') // not case-sensitive
    {
        rate = 0.68;
    } 
    if (gender == 'f' || gender == 'F')
    {
        rate = 0.55;
    }
    if (gender == 'c' || gender == 'C')
    {
        rate = 0.75;
    }

    // determine volume percentage
    if (drink == 'b' || drink == 'B') 
    {
        vol = 5;
    } 
    if (drink == 'w' || drink == 'W')
    {
        vol = 12;
    }
    if (drink == 's' || drink == 'S')
    {
        vol = 38;
    }

    // calculating blood alcohol concentration
    bac = ((litres * 1000) * (vol / 100) * 0.8) / (weight * rate);
    // ((litres * 1000) * (vol / 100) * 0.8) --> formula for alcohol mass
    // (litres * 1000) --> conversion to millilitres

    return bac;
}

int main () // main function for user input/output
{
    // variables to be entered
    char gender, drink;
    int weight;
    float litres;

    // getting user input
    std::cout << "Are you male (m), female (f), or a small child (c)?" << std::endl;
    do
    {
        std::cin >> gender;
        if (gender != 'm' && gender != 'M' && gender != 'f' && gender != 'F' && gender != 'c' && gender != 'C') // check input
        {
            std::cout << "\nInvalid input: Please enter 'm', 'f' or 'c' (capital letters are allowed)." << std::endl;
        }
    }
    while (gender != 'm' && gender != 'M' && gender != 'f' && gender != 'F' && gender != 'c' && gender != 'C');
    // repeat as long as valid input is entered

    std::cout << "\nWhat is your weight (in kg)?" << std::endl;
        do
    {
        std::cin >> weight;
        if (weight < 10 || weight > 400)
        {
            std::cout << "\nInvalid input: Please enter a number bigger than or equal to 10 and smaller than or equal to 400." << std::endl;
        }
    }
    while (weight < 10 || weight > 400);

    std::cout << "\nWhich beverage did you drink? beer: (b), wine: (w), schnapps: (s)" << std::endl;
    do
    {
        std::cin >> drink;
        if (drink != 'b' && drink != 'B' && drink != 'w' && drink != 'W' && drink != 's' && drink != 'S')
        {
            std::cout << "\nInvalid input: Please enter 'b', 'w' or 's' (capital letters are allowed)." << std::endl;
        }
    }
    while (drink != 'b' && drink != 'B' && drink != 'w' && drink != 'W' && drink != 's' && drink != 'S');

    std::cout << "\nHow many litres did you drink?" << std::endl;
    do
    {
        std::cin >> litres;
        if (litres < 0 || litres > 10)
        {
            std::cout << "\nInvalid input: Please enter a number bigger than or equal to 0 and smaller than or equal to 10." << std::endl;
        }
    }
    while (litres < 0 || litres > 10);

    // print the result
    std::cout << std::endl << std::endl << "Your blood alcohol concentration is: "
        << std::fixed << std::setprecision(2) // show only 2 decimal places after the dot
        << BAC (gender, weight, drink, litres) // function call
        << " thousandths." << std::endl;

    return 0;
}

Your problem, as I'm sure you've realised, is the 'left over' characters in the std:cin stream after having read each input. Now, although you can't actually "flush" an input stream , you can clear all 'waiting' input characters, using code like the following before each input:

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

For more discussion on this, see here: How do I flush the cin buffer?

Another point you may need to consider is what happens when any of the input operations fails. You should initialise your variables with 'invalid' values to ensure that the user has actually provided good data:

char gender = '?', drink = '?';
int weight = -1.0;
float litres = -1.0;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM