Попытка узнать о циклах проверки ввода - PullRequest
1 голос
/ 26 февраля 2020

В этой проверке ввода, пока l oop, cerr отображается после вызова вывода моей консоли. Он отображается как «Введите курс: $ Invalid Rate». Например:

Enter rate: $750
Enter rate: $Invalid Rate. 

То же самое делает с do-while l oop. Любой совет или помощь?

#include <iostream>

using namespace std;
#define max_rate 50
#define max_hours 80

int main() {

   // input validation loop (loops until input is valid)
   double rate, hours;

   cout << "enter rate: $";
   cin >> rate;
   cin.ignore();

   while (rate > max_rate){
       if (rate > max_rate){
           cerr << "Invalid Rate." << endl;
       }
       cout << "enter rate: $";
       cin >> rate;
   }

   do {
       if (hours > max_hours) {
           cerr << "Invalid hours." << endl;
       }
       cout << "enter hours: ";
       cin >> hours;

       }
   while (hours > max_hours);


   double pay = rate * hours;
   cout << "$" << pay << endl;
   return 0;

Ответы [ 2 ]

0 голосов
/ 27 февраля 2020

Проверка ввода пользователя - это проверка состояния потока после каждого ввода. Состояние ошибки потока состоит из четырех основных состояний битовой маски goodbit (без ошибок), badbit (неисправимая ошибка), failbit (плохое преобразование / извлечение) и eofbit (конец файла) . Каждое состояние потока может быть проверено с помощью соответствующей функции-члена .good(), .bad(), .fail() и .eof() или при чтении и проверке std :: basic_ ios :: rdstate напрямую.

И .eof(), и .bad() не подлежат восстановлению, .fail() требует, чтобы вы удалили все оскорбительные символы, вызывающие сбой, из потока ввода перед попыткой следующего ввода (или тот же самый ввод, вызвавший сбой, будет прочитан снова), а затем очистить состояние ошибки потока с помощью функции-члена .clear().

При принятии пользовательского ввода надежный подход будет * l 1055 * постоянно, требуя от пользователя предоставления правильного ввода с выдачей достаточной диагностики информировать пользователя о том, что пошло не так, и обрабатывать очистку любого failbit из состояния потока, а также любых оскорбительных или посторонних символов из входного потока перед следующим вводом. Подход довольно прост, просто введите непрерывное l oop, запрос, проверьте состояние потока, выйдите при неисправимой ошибке, .clear() ошибка потока на .fail(), подтвердите ввод в нужном диапазоне и break l oop, если все критерии удовлетворены, и, наконец, удаление всех символов до конца строки перед началом следующей итерации ввода.

Чтобы прочитать rate, чем можно собрать, как показано ниже :

    for (;;) {          /* loop continually until valid input is received */
        std::cout << "\nenter rate: $ " << std::flush;  /* prompt/flush */

        if ( !(std::cin >> rate) ) {
            /* if eof() or bad() (unrecoverable) break read loop */
            if (std::cin.eof() || std::cin.bad()) {
                std::cerr << "  user canceled or unrecoverable stream error.\n";
                return 1;
            }
            else if (std::cin.fail()) {     /* if failbit */
                std::cerr << "  error: invalid double input.\n";
                std::cin.clear();           /* clear failbit */
            }
        }
        else if (rate > max_rate)   /* validate against max_rate */
            std::cerr << "  rate entered exceeds max_rate (" << max_rate << ")\n";
        else    /* all checks passed, good input */
            break;
        /* empty any extraneous character to end-of-line */
        std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
    }

То же самое можно сделать для hours. Вы можете написать функцию, которая обрабатывает запрос и проверку, чтобы сократить некоторые повторения в теле вашего кода, но просто включить циклы проверки для rate и hours вполне подойдет. Содержание и проверка являются важной частью.

Добавление короткого main(), полный пример может быть:

#include <iostream>
#include <limits>

#define max_rate 50     /* good -- if you need a constant, #define one (or more) */
#define max_hours 80

int main (void) {

    double rate, hours;

    for (;;) {          /* loop continually until valid input is received */
        std::cout << "\nenter rate: $ " << std::flush;  /* prompt/flush */

        if ( !(std::cin >> rate) ) {
            /* if eof() or bad() (unrecoverable) break read loop */
            if (std::cin.eof() || std::cin.bad()) {
                std::cerr << "  user canceled or unrecoverable stream error.\n";
                return 1;
            }
            else if (std::cin.fail()) {     /* if failbit */
                std::cerr << "  error: invalid double input.\n";
                std::cin.clear();           /* clear failbit */
            }
        }
        else if (rate > max_rate)   /* validate against max_rate */
            std::cerr << "  rate entered exceeds max_rate (" << max_rate << ")\n";
        else    /* all checks passed, good input */
            break;
        /* empty any extraneous character to end-of-line */
        std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
    }

    for (;;) {          /* loop continually until valid input is received */
        std::cout << "\nenter hours: " << std::flush;   /* prompt/flush */

        if ( !(std::cin >> hours) ) {
            /* if eof() or bad() (unrecoverable) break read loop */
            if (std::cin.eof() || std::cin.bad()) {
                std::cerr << "  user canceled or unrecoverable stream error.\n";
                return 1;
            }
            else if (std::cin.fail()) {     /* if failbit */
                std::cerr << "  error: invalid double input.\n";
                std::cin.clear();           /* clear failbit */
            }
        }
        else if (hours > max_hours) /* validate against max_hours */
            std::cerr << "  hours entered exceeds max_hours (" << max_hours << ")\n";
        else    /* all checks passed, good input */
            break;
        /* empty any extraneous character to end-of-line */
        std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
    }

    double pay = rate * hours;
    std::cout << "\n$" << pay << '\n';
}

Пример использования / Вывод

После того, как вы написали подпрограмму ввода - go попробуйте сломать ее. Преднамеренно вводите неверный ввод и дополнительный посторонний ввод после хороших значений, чтобы убедиться, что вы обрабатываете все аспекты ввода. Минимальный прогон может быть следующим:

$ ./bin/validate_rate_hours

enter rate: $ 56 dollars
  rate entered exceeds max_rate (50)

enter rate: $ I don't care I really want $50!!
  error: invalid double input.

enter rate: $ 50

enter hours: 120 hours and 59 minutes and 59 seconds
  hours entered exceeds max_hours (80)

enter hours: I really want 120:59:59!!
  error: invalid double input.

enter hours: 80

$4000

Понимание и проверка состояний ошибок потока C ++ - ключ к написанию надежных подпрограмм ввода. Посмотрите вещи и дайте мне знать, если у вас есть вопросы.

0 голосов
/ 27 февраля 2020

Ответ: сначала прочитайте, потом проверьте, потом заявите третий. То есть

for (;;) { // the same as while(true)
    cin >> rate;
    if (rate is valid)
        break;
    cout << "Invalid rate\n";
}

И не смешивайте cout и cerr без причины. cout задерживает вывод, накапливая данные во внутреннем буфере, а cerr печатает немедленно. (но cout очищает буфер при использовании cin; также можно явно вызвать cout.flush [или cout << flush]).

...