Безопасно быстрый для да/нет с cin

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

Действительно ли это - хороший способ сделать это? Я происхожу из среды PHP/PERL, которая делает меня довольно опасающимся из использования циклов с условием продолжения.

char type;
while (true) {
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;

    if ((type == 'y') || (type == 'n')) {
        break;
    }
}

Действительно ли это - безопасный способ сделать это, или я открываю меня до мира вреда, который я подозреваю? Каков был бы лучший способ удостовериться, что я получаю вход, который я хочу перед продолжением?

10
задан Levi 7 February 2010 в 03:09
поделиться

10 ответов

Лично я бы сказал:

do
{
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;
}
while( !cin.fail() && type!='y' && type!='n' );
25
ответ дан 3 December 2019 в 13:37
поделиться

Можно использовать

do {
    program;
} while (condition_to_repeat);

, если алгоритм аналогичен Вашему примеру. В противном случае пример "безопасен", но я не уверен в его читабельности.

4
ответ дан 3 December 2019 в 13:37
поделиться

Почему бы не сделать это таким образом?

do
{
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;
}while(  type !='y' && type !='n');
2
ответ дан 3 December 2019 в 13:37
поделиться

Все в порядке. Если вы хотите, чтобы таймаут наступил после ряда неудач, вы можете использовать i<10, но это того не стоит.

1
ответ дан 3 December 2019 в 13:37
поделиться

И не забудьте сделать свой жизнь потенциального пользователя проще объяснять каждый шаг и даже обеспечивать ввод без учета регистра.

#include <iostream>

#define MAX_USER_INPUT_ATTEMPTS 3

int _tmain(int argc, _TCHAR* argv[])
{
char input_value = ' ';
int current_attempt = 1;

while(true)
{
    std::cout << "Please confirm your choice (press y[es] or n[o] and Enter): ";

    std::cin >> input_value;

    input_value = tolower( input_value );

    if(input_value=='y' || input_value=='n')
    {
        break;
    }
    else
    {
        std::cout << "You have used " << current_attempt << " of " << MAX_USER_INPUT_ATTEMPTS << " attempts" << std::endl;
        ++current_attempt;
    }

    if( current_attempt > MAX_USER_INPUT_ATTEMPTS )
    {
        std::cout << "Warning: Maximum number of attempts reached." << std::endl;
        break;
    }
}

return 0;
}
1
ответ дан 3 December 2019 в 13:37
поделиться

Линейный вход не обязательно должен быть многословным, вы можете сделать его кратким, с одной единственной функцией, которую вы пишете один раз, которая все еще обрабатывает угловые случаи:

bool yesno_repeat(char const* prompt) {
  using namespace std;
  while (true) {
    cout << prompt << " [yn] ";
    string line;
    if (!getline(cin, line)) {
      throw std::runtime_error("unexpected input error");
    }
    else if (line.size() == 1 and line.find_first_of("YyNn") != line.npos) {
      return line == "Y" || line == "y";
    }
  }
}

int main() try {
  if (yesno_repeat("Blow up?")) {
    take_off_every<Zig>(); // in the future, a zig is a nuclear missile...
  }
  return 0;
}
catch (std::exception& e) {
  std::cerr << e.what() << '\n';
  return 1;
}
1
ответ дан 3 December 2019 в 13:37
поделиться

Конструкция do ... while вроде как создана для этого, но вы также можете выполнять всю работу в условии цикла:

while (std::cout << "Were you admitted [y/n]\n" && std::cin >> answer && !(answer == 'y' || answer == 'n'));

:)

И если вы не хотите проверять успех std :: cin >> answer (например, хотите бесконечный цикл с помощью Ctrl + Z), вы можете заменить запятую && :)

Не совсем серьезно, хотя мне кажется, что подсказка в условии иногда может улучшить логику таких циклов (избегайте break ).

0
ответ дан 3 December 2019 в 13:37
поделиться

Я никогда раньше не программировал на PERL / PHP, но, основываясь на вашем вопросе и приведенном здесь примере, дает простое решение.

    char c;
while(true){
    cout << "Were you admitted? [y/n]" << endl;
    cin >> c;
    if(c == 'y')
        break;
}
cin.get(c);
return 0;

Вы будете продолжать получать запросы, пока не введете «y» после ввода «y», эта простая программа выйдет.

0
ответ дан 3 December 2019 в 13:37
поделиться

Я вижу здесь две "проблемы". Первая - это использование while( true ). Я не думаю, что это хорошая практика (хотя, возможно, для многих это дело вкуса). Однако прерывание внутри цикла интересно для поиска:

for(i = 0; i < MAX; ++i) {
  if ( v[ i ] == searchedElement ) {
      break;
  }
}

Это не требует пояснений: вы бежите до конца вектора, но если элемент найден, вы прерываетесь, не дойдя до него. Это оправдано.

Что касается получения информации из консоли, вы можете столкнуться с большими проблемами при чтении непосредственно из cin, например, вам будет возвращено содержимое только до первого пробела, если он есть. getline() - это служебная функция, которая читает в строку, что (почти) всегда безопасно. getline() определена в заголовке утилиты. Вам также понадобится заголовок string. И cstdio, если вы хотите использовать EOF.

int main()
{
    int ch;
    std::string type;

    do {
        getline( std::cin, type );

        if ( cin.fail() ) {
            ch = EOF;
            break;
        }

        ch = tolower( type[ 0 ] );
    } while( ch != 'y' && ch != 'n' );

    // interesting things here...

    return 0;
}
0
ответ дан 3 December 2019 в 13:37
поделиться

Вероятно, вы можете извлечь урок из электронной почты клиентов.

Они работают, сначала запрашивая у сервера список идентификаторов сообщений. Как только у клиента есть этот список, он сравнивает его с локальным хранилищем данных, чтобы проверить, отличается ли что-либо от этого.

Если есть разница, нужно одно из пары действий. 1. Если он существует на клиенте, но не на сервере И мы IMAP, то удалить локально. 2. Если он существует на сервере, но не на клиенте, загрузите оставшуюся часть сообщения.

В вашем случае сначала запросите все идентификаторы. Затем отправьте последующий запрос, чтобы получить все данные для тех, которых у вас еще нет.

Если существует ситуация, когда запись может существовать локально, но может быть обновлена с момента последней загрузки на сервер, запрос должен содержать последнюю обновленную дату.

-121--4617244-

Создайте структуру данных, которая представляет клавиатуру и кодирует строку, столбец, руку и палец, используемые для ввода каждого символа. Напишите функцию, которая, будучи представлена символом, предоставляет список «простых в вводе» символов, основанных на гибких правилах, которые вы разрабатываете. Она может опираться на другую функцию, которая вычисляет расстояние между клавишами.

Лично я не нахожу ввод букв одной рукой дважды медленным: только если предыдущая буква использовала палец, который был слишком близко, это трудно. Например, XQ трудно напечатать, потому что моя рука должна двигаться вверх, чтобы справиться с соседними пальцами, необходимыми для их ввода. Но мне совсем не кажется, что БК трудно печатать, потому что, пока мой указательный палец все еще работает над B, мой розовый палец может направиться к Q.

Также гораздо проще набрать AW, чем QS, потому что безымянный палец длиннее и так естественно умещается на W, в то время как пинки на A, в положении вблизи покоя, в то время как QS требует растяжения пинки и одновременного конфликтующего мышечного хруста безымянного пальца.

Если вы начнете составлять карту каждого письма друг против друга, вы вскоре найдете разумный способ представить различные аспекты легкости или сложности. Обобщая мой пример XQ/BQ, можно сделать, что однорядные изменения требуют расстояния в 2 или более пальцев, 2-рядные изменения требуют расстояния в 3 пальца, а 3-рядные изменения (числа, возможно) требуют альтернативных рук.

Я также замечаю, что немного большее расстояние между WD и IL, чем SE и KO, также изменяет сложность из-за слегка зазубренного размещения клавиш.

При некотором анализе (я рекомендую использовать Excel для «отображения» сложности ввода) я уверен, что вы можете придумать алгоритм, который поможет вам построить простые в использовании слова.

Если возможно, попробуйте ввести хотя бы одно число и также попробуйте использовать места.

-121--2856354-

Лично я бы сделал подсказку отдельной функцией, это делает ее вывод подсказки и чтение ответа логическим выражением, чтобы поместить в цикл while.

Проверка успешности считывания имеет решающее значение для правильного функционирования кода.

Я бы также предпочел использовать std:: getline , чтобы получить строку за раз, так как это помогает уменьшить ошибки, вызванные чтением остальной половины строки чтения, которая была результатом частичного чтения более ранних ответов пользователя.

bool PromptForChar( const char* prompt, char& readch )
{
    std::string tmp;
    std::cout << prompt << std::endl;
    if (std::getline(std::cin, tmp))
    {
        // Only accept single character input
        if (tmp.length() == 1)
        {
            readch = tmp[0];
        }
        else
        {
            // For most input, char zero is an appropriate sentinel
            readch = '\0';
        }
        return true;
    }
    return false;
}

void f()
{
    char type = '\0';

    while( PromptForChar( "Were you admitted? [y/n]", type ) )
    {
        if (type == 'y' || type == 'n')
        {
            // Process response
            break;
        }
    }
}
9
ответ дан 3 December 2019 в 13:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: