cin.clear()的意外行为;

时间:2014-11-24 07:16:41

标签: c++ cin

我想做什么:

我想要一个将名称存储到char*

数组中的代码

我打算使用cin.getline和cin.clear进行输入 错误安全。

规则是:在输入.后,必须存储最多10个名称或中断。

在这两种情况下,名称必须每行输入一个cout 1名称。

我的循环应该做什么:占用MAX_NAME_LEN字母,扩展max len的所有内容应该在下一个循环开始之前从stdin中丢弃。

do
{
    cin.getline(szInputRef, MAX_NAME_LEN);
    sizeLastLen = cin.gcount();
    szpNames[sizeIndex] = new char[sizeLastLen];
    strncpy (szpNames[sizeIndex], szInputRef, sizeLastLen);
    szpNames[sizeIndex][sizeLastLen] = '\0';
    sizeIndex++;
    cin.clear();
}
while ((sizeIndex < 10) &&(szpNames[sizeIndex - 1][0] != '.'));

for (sizeIndex = 0; sizeIndex < 10; sizeIndex++)
{
    if (szpNames[sizeIndex][0] == '.')
    {
        break;
    }

    cout << szpNames[sizeIndex] << endl;
}

但是实际发生了什么:扩展MAX_NAME_LEN字母数量的输入被视为下一个输入而没有检查。所以我们假设我们说测试用例MAX_NAME_LEN是3

并输入:

ig
se
nols

输出将是:

ig
se
nol
s

如果输入是&gt; (MAX_NAME_LEN * 2) 应用程序崩溃,第二次输入检查似乎没有出现。 毕竟阅读有关cin.clear()

的文档

我无法理解为什么在调用cin.clear()之后输入甚至不再存在了。 甚至没有任何扩展输入行为的Clou在没有cin.getline检查的情况下存储,因此应用程序可以崩溃。

有人能解释我的理解错误或我的代码中出现了什么逻辑错误吗?

1 个答案:

答案 0 :(得分:1)

丢弃输入流中的所有内容通常不是一件有用的事情。例如,某人可能会向stdin提供一个文件,在这种情况下,您将丢弃所有内容,或者您​​的操作系统可能会以不同于预期的缓冲区进行缓冲,并且您最终会得到不可预测的结果。你真正想要做的是忽略当前输入行的其余部分。最简单的方法是说

#include <iostream>
#include <limits>

std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

其中std::numeric_limits<std::streamsize>::max()std::streamsize类型中的最大数字,std::istream::ignore的特殊情况,表示无穷大。这意味着:忽略无限多个字符或下一个'\n',以先到者为准。

但是,您无法无条件执行此操作,因为如果缓冲区足够大,std::istream::getline会消耗换行符;你忽略了其他每一行。只有当行太长而无法放入缓冲区时,才必须执行它。发生这种情况时,std::istream::getline设置failbit,因此我们最终会使用

if(std::cin.fail()) {
  std::cin.clear();
  std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

顺便说一句,您还应该防范不可恢复的I / O错误和错误&#34;例如文件结束。目前,如果有人在你的程序运行时按下Ctrl + D(Unix)或Ctrl + Z(Windows),它会做有趣的事情。当然,如果您使用std::stringstd::getline,则会更容易。