cin.getline()不接受输入的问题

时间:2020-01-22 19:08:31

标签: c++ validation cin getline input-buffer

我正在使用cin.getline()将用户输入存储在字符数组中,并尝试解析输入以仅允许输入1到4的数字。在特定的情况下,一切正常:在第一次尝试中输入正确的输入,或者输入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]

我已经尝试了从清除输入缓冲区到将字符数组重置为null终止符的所有尝试,以尝试查看它是否仍保留先前输入的值(例如在意外行为中,如果仍然存在“ tw”在记忆中)。我认为我可能遇到类似于this discussion的问题,但我不确定100%。当我尝试清除输入缓冲区时,它会等待第二组输入,但我不确定为什么。当我打印inputLength的结果时,在运行“意外行为”后,它表明当我只输入1时,数组中仍然有2或3个字符。删除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降低一个值。即使再次输入1,即使再次输入,输入的9个字符也会降为8。

2 个答案:

答案 0 :(得分:0)

我能够使用Visual Studio并观看inputLengthuserInput变量。 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;
}

答案 1 :(得分:0)

您的代码中有多个问题,迟早会发现。

顺便说一句。您当前的代码无法编译。我假设您在;之后确实有cout << "Correct input.",并且在}if的右花括号之间有一个return,否则您的示例将永远不会循环一次。

您是否提了疑问

您没有清除userInput (并且您的sizeOfCharArray还没有为此做好准备)。

让我们逐步介绍您的代码:

  1. userInput[maxInput] = { "\0" }; //userInput contains all null characters
  2. 用户输入rwt
  3. userInput包含"rwt\0"
  4. 您的代码正确地将其视为无效输入,然后再次要求输入
  5. 用户输入1
  6. userInput被用户输入的字符串覆盖,但是它不会事先清除。现在它包含1\0t\0
  7. sizeOfCharArray计算所有个非空字符并返回2。
  8. 您的循环继续要求输入。

您返回本地变量的地址

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)并且变量为零(自C ++ 11起),它将提高其int位。如果将fail位置1,则good()方法将返回false(即流状态不佳)。在下一次迭代中,我们清除标志和流中所有剩余的输入。
您还可以在循环中检查整数的有效范围(在此处作为单独的函数完成)。

我们使用return语句打破了循环。如果一切正确(即,流成功读取了正确的输入类型,并且输入在有效范围内),我们会将最终值返回给用户。


与qoutes有关的问题:Single quotes vs. double quotes in C or C++。为了您自己的心理健康,请不要随意添加符号,直到编译器停止显示错误为止,从不是个好主意。编译器是您的朋友,他将帮助您发现问题,但前提是您需要帮助。