c ++ isalnum бесконечный цикл - PullRequest
2 голосов
/ 30 марта 2011

Привет!

Давайте на этот раз обрежем лишнее вступление и перейдем прямо к делу.

У меня проблема в C ++ с использованием метода isalnum.

код:

int playAgainst = 0;
do
{
    cout << "Who do you want to play against?(1/2)\n";
    cout << "1: Human player\n";
    cout << "2: Computer player\n";
    cin >> playAgainst
} while(!isalnum(playAgainst) && playAgainst != 0);

Как видно из кода, я предоставляю пользователю выбор. Играть против человека или против компьютера.

Я хочу, чтобы пользователь вводил что-либо еще, а затем целочисленное значение (cin >> playAgainst), чтобы повторить вопрос. Однако, если я ввожу символ или строковое значение, он продолжает бесконечно повторяться. Я не уверен на 100%, но было бы очевидно, если бы проблема заключалась в том, что значение non int уже сохранено в качестве значения для playAgainst. Это?

Или это единственная возможность сохранить как символ / строку, а затем проверить?

Если последнее имеет место, возникает новая проблема. isalnum принимает только int как параметр, по крайней мере из того, что я знаю. Как я буду проверять, является ли эта строка или символ целочисленным?

Спасибо, что нашли время, чтобы прочитать. И, надеюсь, я скоро приму ответ как ответ ^^

Спасибо всем за ответы. Я получил то, что хотел, и все было решено.

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

Ответы [ 6 ]

2 голосов
/ 30 марта 2011

Снимите отметку isalnum(). cin >> playAgainst преобразует все, кроме числа, в ноль, который будет пойман второй проверкой. Обратите внимание, что это только опция, потому что ноль не является допустимым вводом.

isalnum() полезно, если вы сами интерпретируете символы, но в этом случае поток уже сделал это для вас.

2 голосов
/ 30 марта 2011

Сделайте playAgainst a char и сравните с '0', а не 0. Прямо сейчас пользователь должен ввести код ASCII (или любой другой набор символов) для символа '1' или '2'.

isalnum не будет работать на int s вне допустимого диапазона char, за исключением EOF. (Тот факт, что он принимает аргумент int, является остатком от C, который имеет правила целочисленного продвижения, отличные от C ++. для размещения EOF.)

1 голос
/ 30 марта 2011

Проблема в том, что вы вводите int, а не char.И если текст на входе не является целым, то ввод не выполняется.В этом случае playAgainst не изменяется, и ошибка запоминается в std::cin до тех пор, пока вы явно не очистите ошибку.И ввод из потока в состоянии ошибки не работает.Что вы, вероятно, хотите сделать, это

  1. Введите один символ: если вы не хотите пропускать пробелы, используйте `std :: cin.get (ch)` или `ch = std ::cin.get () `.(В последнем случае `ch` должен быть` int`, так как он также должен обрабатывать `EOF`. С другой стороны, вы можете напрямую использовать` :: isalnum` для него, что нельзя сделать, если `ch` является `char`.
  2. Полностью проверьте правильность ввода: не просто` :: isalnum`, а скорее, является ли ввод допустимым селектором в вашем списке. Что-то вроде:
        ch != EOF && std::find( legalChars.begin(), legalChars.end(), (char)ch ) != legalChars.end()
    
  3. В случае ошибки очистите все оставшиеся входные данные, скажем с помощью:
               std::cin.ignore(INT_MAX, '\n');
    

На практике вы, вероятно, захотите трактовать EOF иначе, чем ошибочную команду.(Если вы не очистите ввод после EOF, вы не сможете больше ничего читать. Но, вероятно, если вы получили EOF, это потому, что пользователь сдался и не хочет пытатьсядалее.)

Наконец, вероятно, предпочтительнее хранить всю информацию в общем месте, используя таблицу:

struct Command
{
    char        op;
    char const* prompt;
    void (*     func)();
};

Затем вы перебираете таблицу из них для выводаподскажите, найдите ли он допустимый символ и, наконец, вызовите функцию для записи, которую выound.Или определите абстрактный базовый класс, конкретный класс, производный от него для каждой команды, и используйте std::map<char, AbstractBase*> для отображения и т. Д. Очень C ++, но, возможно, немного излишним для такого простого случая.

1 голос
/ 30 марта 2011

Это потому, что вы не очищаете буфер. Когда ввод недействителен, вам нужно очистить его из буфера, и затем вы можете перейти к следующему вводу, иначе вы пытаетесь извлечь один и тот же ввод каждый раз (что не удается, потому что это тот же неверный ввод), и таким образом войти в бесконечный цикл.

1 голос
/ 30 марта 2011

Вот как компилятор будет реализовывать isalnum:

int isalnum (int ch)
{
  return (ch >= 'a' && ch <= 'z') || 
         (ch >= 'A' && ch <= 'Z') || 
         (ch >= '0' && ch <= '9');
}

Так что вы можете написать этот фрагмент кода в вашем собственном коде, и он будет эквивалентен встроенной версии isalnum.

0 голосов
/ 30 марта 2011

Почему бы не использовать isdigit () .

...