【问题标题】:Problems with cin.getline() not accepting inputcin.getline() 不接受输入的问题
【发布时间】:2020-01-22 19:08:31
【问题描述】:

我正在使用 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]

我已经尝试了从清除输入缓冲区到将字符数组重置为空终止符以尝试查看它是否仍然保留先前输入的值(例如在意外行为中,如果“tw”仍然存在)在记忆中)。我想我可能有类似this discussion 的问题,但我不是 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 降低一个值。即使只输入了1,再次要求输入时,输入 9 个字符也会减少到 8 个。

【问题讨论】:

  • 您是否在代码中使用cin &gt;&gt; 以及cin.getline()?或从此流中提取的任何其他格式?
  • 另外,*"\0" 会触发我的 UB 感觉(尽管我对此不是 100% 确定)。你想要'\0'(单个字符)。
  • @Yksisarvinen ,我目前只使用 cin.getline() 。感谢您的更正,我的代码中有"\0",但在编译器对我大喊大叫后添加了*。上面我也改了。
  • 对我来说,我无法重现意外行为。
  • 您的代码中有一些拼写错误,例如 ` cout ValidateInput 缺少结尾 }。也许只是放错了括号,因为现在while (!correctInputBool) {总是会遇到return userInput;,所以这种形式的循环没有意义。

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


【解决方案1】:

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

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

您提到的问题

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

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


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

【讨论】:

    【解决方案2】:

    我能够使用 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;
    }
    

    【讨论】:

    • 这应该行不通,您在阅读后立即将整个缓冲区设置为\0。更新的部分可能应该在cin.getline(...)之前出现?
    • @churill 是的,我的错。现在已经修复了
    猜你喜欢
    • 1970-01-01
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 2021-11-17
    • 2018-12-31
    • 2014-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多