【问题标题】:Safe operation to clear the empty input buffer in C++在 C++ 中清除空输入缓冲区的安全操作
【发布时间】:2018-03-13 01:08:50
【问题描述】:

我正在查看this 的帖子和其他一些帖子。如果在输入缓冲区已经为空时调用 ignore() 会发生什么?我在下面的代码中观察到,如果在缓冲区已经为空时调用 ignore(),它将不起作用并等待首先输入某个字符。

int main(void)
{
    char myStr[50];
    cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
    cout<<"Enter the String\n";
    cin>>myStr;
    // After reading remove unwanted characters from the buffer
    // so that next read is not affected
    cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
}

cin.clear() 在ignore() 之后如果缓冲区看起来已经是空的,则会产生进一步的问题。我想在 cin() 之后清除缓冲区是安全的。但是如果我不知道输入缓冲区的状态并且即使它已经是空的我也会清除呢?我是否必须先使用 cin.fail() 或类似的方法检查输入缓冲区是否为空?

其次,cin 本身可能不安全,因为不允许使用空间。所以 getline() 是由一些 SO 帖子建议的,如给定的here。但是 getline() 是否也需要清除输入缓冲区或者它总是安全的?下面的代码是否可以正常工作(现在可以正常工作,但现在确定它是否是安全代码)。

void getString(string& str)
{
    do
    {
        cout<<"Enter the String: ";
        getline(std::cin,str);
    }  while (str.empty());
}

其他 SO 参考: Ref 3

【问题讨论】:

    标签: c++ inputstream


    【解决方案1】:

    崩溃main

    int main(void)
    {
        char myStr[50];
        cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
    

    一个坏主意,但你已经注意到了。流中必须有换行符,否则您就坐等换行符。如果用户没有预料到这种行为,您可能会等待很长时间并让用户感到沮丧。这是一个糟糕的场景。

        cout<<"Enter the String\n";
        cin>>myStr;
    

    也是一个坏主意,但出于不同的原因。 &gt;&gt; 不知道它应该在 49 个字符处停止以防止溢出 myStr。坏事发生在第 50 个字符处。

        // After reading remove unwanted characters from the buffer
        // so that next read is not affected
        cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
    

    这个是安全的。 &gt;&gt; 不会使用换行符或任何其他空格,并且为了让流从控制台移交数据,必须有人按下回车键并提供换行符。

    }
    

    一般的经验法则是不要ignore,除非你有理由ignore,如果你有理由,请立即忽略。不要等到对ignore 的下一个流操作之前,因为如果这个操作是第一个呢?或者之前的操作没有给ignore留下任何东西? ignore 在流中留下你想要的ignored 的操作之后。所以

    std::string getfirstword()
    {
        std::string firstword;
        if (std::cin >> firstword)
        {
            cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
            return firstword;
        }
        return ""; // or perhaps
        // throw std::runtime_error("There is no first word.");
        // is more appropriate. Your call.
    }
    

    很好,但是

    std::string getfirstword()
    {
        cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
        std::string firstword;
        if (std::cin >> firstword)
        {
            return firstword;
        }
        return "";
    }
    

    在所有圣洁者的眼中是一种冒犯。不要这样做。

    至于getline,它得到一条线。一直到文件末尾或行尾,以先到者为准。它还为您吃掉了行尾,因此您不必担心以后会有杂散的换行符刺痛您的圆润。

    如果您只想要部分线路,则必须将其分解。典型用法类似于

    std::string line;
    if (std::getline(std::cin,line))
    {
        std::istringstream istr(line);
        std::string firstword;
        if (istr >> firstword)
        {
            // do something with firstword
        }
        else
        {
            // there is no firstword. Do something else.
        }
    }
    

    getline 读取所有内容,包括换行符。它不再在流中,所以我认为这是安全的。您不必担心垃圾在生产线末端徘徊。不过,您可能不得不担心下一行。

    【讨论】:

    • 感谢您的精彩解释。但是我猜带有停止字符的 getline() 可能会在缓冲区中留下换行符。例如:如果是 getline(cin,str1,'z');获取线(cin,str1);第二个 getline() 不会等待用户输入。如果空格在输入缓冲区中,getline() 也不会像 cin 那样忽略空格。
    • @Rajesh 是的,如果您使用不同的分隔符,该分隔符将被消耗并停止收集。在这种情况下,换行符将被视为常规字符,并作为收集字符串的一部分返回,或者如果尚未遇到则留在流中。如果您有多个分隔符,一个简单的技巧是使用多个 getlines all 和适当的分隔符。 getline 转换为 stringstring 转换为 istringstreamgetline,在 istringstream 上加上分隔符以获取令牌。
    • 您说过“一般的经验法则是不要忽略,除非您有理由忽略,如果您有理由,请立即忽略”。我们应该如何处理我们不知道输入是否包含某些数据的情况?考虑我们为整数输入浮点数的情况。在这种情况下,数据会被截断,但我猜输入缓冲区没有被清除。我想写模板来处理这个。但是因为这个而卡住了
    • 当我需要精确控制时,我倾向于使用一点 C。我读了一个 string,然后用 the strtol family of functions 之一解析它。注意str_end 参数。如果它不为空,则未到达string 的末尾,您可以根据需要进行处理。无论如何,除非输入被严重破坏并且用户在错误的位置或类似的地方丢弃了空白字符,否则流中没有任何内容。您不能总是保存用户。有时你必须 ignore 到最后或类似的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-08
    • 2011-12-15
    • 2016-12-10
    • 1970-01-01
    相关资源
    最近更新 更多