我想做什么:
我想要一个将名称存储到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检查的情况下存储,因此应用程序可以崩溃。
有人能解释我的理解错误或我的代码中出现了什么逻辑错误吗?
答案 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::string
和std::getline
,则会更容易。