Проблемы с тем, что cin.getline () не принимает ввод - PullRequest
0 голосов
/ 22 января 2020

Я использую cin.getline () для хранения ввода пользователя в массиве символов и пытаюсь проанализировать ввод, чтобы разрешить ввод только чисел от 1 до 4. Все работает нормально при заданном c наборе обстоятельств: правильный ввод вводится с первой попытки, ИЛИ вводится 2 или менее символов, а правильный ввод вводится после. Ниже приведен пример.

[Expected behavior]
Enter input: 1 [ENTER]
Input accepted

[Expected behavior]
Enter input: rw [ENTER]
Incorrect input. Please try again.
Enter input: 1 [ENTER]
Input accepted

[Unexpected behavior]
Enter Input: rtw [ENTER]
Incorrect input. Please try again.
Enter Input: 1 [ENTER]
Incorrect input. Please try again.
Enter input: 1 [ENTER]
Incorrect input. Please try again.
[This will continue indefinitely]

Я перепробовал все: от очистки буфера ввода до сброса массива символов до нулевых терминаторов в попытке выяснить, сохранил ли он значения из предыдущего ввода (как в неожиданное поведение, если «tw» как-то все еще был в памяти). Я думаю, что у меня может быть проблема, подобная этой дискуссии , но я не уверен на 100%. Когда я пытаюсь очистить входной буфер, он ждет второй набор ввода, и я не уверен, почему. Когда я печатаю результаты inputLength, после запуска «неожиданного поведения», это показывает, что в массиве все еще есть 2 или 3 символа, когда я только ввел 1. При удалении cin.clear () / cin.ignore (), второй ввод не требуется, но тогда происходит описанное выше поведение. Я признателен за любую помощь.

Я разместил соответствующий код ниже.

char* ValidateInput() {
    const int maxInput = 25;
    char userInput[maxInput] = { "\0" };
    int inputLength = 0;
    bool correctInputBool = false;

    while (!correctInputBool) {
        // subtract 1 to allow for null terminator at end of array
        cin.getline(userInput, (maxInput - 1), '\n');


        // I have tried both versions of cin.ignore() below, but neither works
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        //cin.ignore(numeric_limits<streamsize>::max());



        // calculate how many characters user entered
        inputLength = sizeOfCharArray(userInput, maxInput);

        // I do other things here, there isn't a problem with this. For now, assume all 1-character input is acceptable
        if (inputLength == 1) {
            cout << "Correct input." << endl;
            correctInputBool = true;
        }

        if (!correctInputBool) {
            cout << "Sorry, that input is incorrect. Please try again." << endl;
            cout << "Please enter a number between 1 and 4." << endl;
        }
        return userInput;
    }

int sizeOfCharArray(char input[], int maxSize) {
    // all values in input are set to "\0", so count all characters that are not null
    int userSize = 0;
    for (int index = 0; index < maxSize; index++) {
        if (input[index] != '\0') {
            userSize++;
        }
    }
    return userSize;
}

РЕДАКТИРОВАТЬ: я заметил, что когда я ввожу более 3 символов, при следующем запуске всегда будет сбрасывать inputLength на одно значение ниже Ввод 9 символов уменьшается до 8 при повторном запросе ввода, даже если был введен только 1.

Ответы [ 2 ]

1 голос
/ 22 января 2020

В вашем коде есть несколько проблем, которые вы найдете рано или поздно.

Кстати. Ваш текущий код не компилируется. Я предполагаю, что у вас есть ; после cout << "Correct input." и } между закрывающей скобкой if и return, иначе ваш пример никогда не будет l oop даже один раз.

Проблема, которую вы упомянули

Вы не очищаете userInput (и ваш sizeOfCharArray не готов к этому).

Давайте go шаг за шагом с вашим кодом :

  1. userInput[maxInput] = { "\0" }; //userInput contains all null characters
  2. Пользовательские данные rwt
  3. userInput содержит "rwt\0"
  4. Ваш код правильно видит его как недействительный input и снова запрашивает ввод
  5. Вводимые пользователем данные 1
  6. userInput перезаписывается введенной пользователем строкой, но заранее не очищается . Теперь он содержит 1\0t\0
  7. sizeOfCharArray, вычисляет все ненулевые символы и возвращает 2.
  8. Ваш l oop продолжает запрашивать ввод.

Вы возвращаете адрес локальной переменной

После ValidateInput массив userInput не работает. Ушел навсегда. И вы возвращаете адрес в мертвый массив, память, которую компилятор может использовать по своему усмотрению.

Ваш код слишком запутанный

Это часто недооцениваемая проблема, но простой код = легкое чтение = меньше ошибок.

Вы хотите целое число, верно? Так как же при чтении целого числа из входных данных ?

int GetInput() {
    int result {};
    while (true) { //infinite loop
        cin >> result;

        if(!cin.good()) {
            cout << "Input wasn't a number, please try again.\n";
            cin.clear(); //clear flags that were raised
            cin.ignore(numeric_limits<streamsize>::max(), '\n'); // skip any input remaining in the stream
        } else if (!InputIsValid(result)) {
            cout << "Input not in 1-4 range, please try again.\n";
        } else {
            return result;
        }
    }
}

bool InputIsValid(int input) {
    return input >= 1 && input <= 4;
}

std::cin повысит свой бит fail, если не удастся извлечь запрашиваемый тип (в данном случае int), и переменная обнуляется (начиная с C ++ 11). Если бит fail установлен, метод good() вернет false (т.е. поток не находится в хорошем состоянии). На следующей итерации мы очищаем флаги и все оставшиеся входные данные из потока.
Вы также можете проверить действительный диапазон целого числа в l oop (здесь это делается как отдельная функция).

Мы вырвались из l oop, используя оператор return. Если все правильно (т. Е. Потоку удалось прочитать правильный тип ввода, а ввод находится в допустимом диапазоне), мы возвращаем конечное значение пользователю.


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

0 голосов
/ 22 января 2020

Я смог использовать Visual Studio и смотреть переменные inputLength и userInput. inputLength действительно только опустил 1 значение, потому что нулевой терминатор был добавлен в конец ввода. Из-за этого

userInput = "asdf" // with the reminaing values being '\0'
inputLength = 4

userInput = "2'\0'df" // with the following being held in memory: 2 '\0' df '\0' '\0' . . .
inputLength = 3

Когда я пытался напечатать значения userInput, я только когда-либо видел 2 из-за нулевого терминатора; хотя значения все еще были там, они не печатали, потому что компилятор увидел '\0' и решил, что после этого ничего не было. В результате, когда я позвонил sizeOfCharArray, были подсчитаны все значения, которые не были нулевыми терминаторами, включая значения из предыдущего ввода.

Мой обновленный код указан ниже.

char* ValidateInput() {
    const int maxInput = 25;
    char userInput[maxInput] = { "\0" };
    int inputLength = 0;
    bool correctInputBool = false;

    while (!correctInputBool) {         
        // updated section
        for (int index = 0; index < maxInput; index++) {
            userInput[index] = '\0';
        }
        // subtract 1 to allow for null terminator at end of array
        cin.getline(userInput, (maxInput - 1), '\n');

        // calculate how many characters user entered
        inputLength = sizeOfCharArray(userInput, maxInput);

        // I do other things here, there isn't a problem with this. For now, assume all 1-character input is acceptable
        if (inputLength == 1) {
            cout << "Correct input."
            correctInputBool = true;
        }

        if (!correctInputBool) {
            cout << "Sorry, that input is incorrect. Please try again." << endl;
            cout << "Please enter a number between 1 and 4." << endl;
        }
        return userInput;
    }

int sizeOfCharArray(char input[], int maxSize) {
    // all values in input are set to "\0", so count all characters that are not null
    int userSize = 0;
    for (int index = 0; index < maxSize; index++) {
        if (input[index] != *"\0") {
            userSize++;
        }
    }
    return userSize;
}
...