错误的输入将导致程序退出
Wrong Inputs will cause the program to exit
看看这段代码:
#include <iostream>
using namespace std;
int main()
{
string s;
int n;
float x;
again:
cout << "Please Type this: ABC456 7.8 9 XYZn";
cin >> s >> n >> x >> s;
cout << "nDo you want to try Again(y/n)? ";
char t;
cin >> t;
if (t=='y' || t=='Y')
goto again;
return 0;
}
只需尝试键入"ABC456 7.8 9 XYZ"并按回车键,它将导致程序退出,然后提示用户重试。我知道输入是错误的,它们不在它们的类型中,但为什么它会导致退出?以及如何避免这种退出?
更改
cin >> s >> n >> x >> s;
自
cin >> s >> x >> n >> s;
当您输入7.8
作为第二个输入时,但您将其收集在整数变量而不是浮点变量中。因此,当您输入:
ABC456 7.8 9 XYZ
s
得到ABC456
,n
得到7
(因为它是int类型,输入缓冲区仍然有.8 9 XYZn
(。接下来n
.8
,最后s
"9"
。现在输入缓冲区已包含XYZn
。下次当您将输入读入t
以获得用户的选择时,X
被读入t
并且由于它不是y
或Y
,循环退出。
在cin
后输入调试行
cout << "s = " << s << " n = " << n << " x = " << x;
并运行
Please Type this: ABC456 7.8 9 XYZ
ABC456 7.8 9 XYZ
s = 9 n = 7 x = 0.8
显然,第一个ABC456被读入字符串s
。下一个是整数,因此只有7
被读入n
,0.8
部分被读入float
x
。现在下一个输入9
再次分配给s
,因此s
的最终值是字符串"9"。现在,X
的第一个字符被输入到下一个cin
,在那里它被分配给t
。要确认,只需在输入t
后插入另一个调试行cout << "nt = " << t;
。因此,if
为假,t
的值分配给"X",因此程序退出。
如果你输入ABC456 7.8 9 YZ
程序将再次要求输入,就像现在t
一样,会有"Y"。
回答 https://stackoverflow.com/a/10379322/924727 expalins 会发生什么。关于为什么,我们必须稍微了解一下哲学。
C++流模型不被认为是"人类交互":它是将几乎无限的字符序列转换为空间分隔的"值"列表的通用转换器,以转换为提供的"变量"。
没有"对话的输入和输出交错"的概念。如果将输入写入文本文件,例如 myinput.txt
(取消正确的输入(
ABC456 9 7.8 XYZ
Y
ABC456 5 6.7 XYZ
N
并从命令提示符下打开您的程序,例如
myprogram < myinput.txt
您的程序将运行...并且不需要"暂停"来查看输出,因为没有人坐在那里查看并回答它。
程序暂停等待用户输入不是因为cin >>
,而是因为cin
未处于失败状态,缓冲区为空,缓冲区重新映射的源是控制台。在返回之前等待""的是控制台,而不是 cin。
当cin >> n
被调用时...
- 调用
operator>>
函数,它... - 从流区域设置中获取num_get方面,并调用其 get 函数...
- 重复调用流缓冲区
sbumpc
以获取数字并计算数字值。 - 如果缓冲区有内容,它只是一个接一个地返回其字符。当没有更多的字符存在时(或者如果它是空的(......
- 缓冲区要求操作系统从低级文件中读取。
- 如果文件是控制台,则调用控制台内部行编辑器:
- 这使得控制台卡住,让用户按字符和一些控件(例如退格键(,直到按 Enter 时
- 控制台行编辑器将行返回到操作系统,该操作系统将允许内容可用于输入 CON 文件...
- 它由填充自身的缓冲区读取(在将读取字符传递到 cvt 区域设置方面之后,但这是一个细节(。
- 现在自己做回报展开。
所有这些机制使得这样一个事实:如果您键入的次数超过要求,缓冲区内容仍然可用于接下来的>>
调用,无论它是否是另一个程序行。
适当的"更安全"解析要求在读取输入后,清除流状态,并在下一'n'
之前忽略以下内容。这通常通过
cin.clear();
cin.ignore(numeric_limits<std::streamsize>::max(), 'n');
这样,键入的任何内容都会被丢弃,下一个cin>>
找到一个没有数据的缓冲区(只有'n'
,它被修剪为"开始空间"(,从而导致控制台再次进入行编辑模式。
当流提取运算符>>
遇到无效输入时,它会将流置于不再提取输入的模式。
您可以使用布尔测试(如 if ( cin )
(检测此模式,并使用 cin.clear()
重置它。这样做之后,无效的输入将保留在cin
的输入缓冲区中,因此您需要以某种方式对其进行处理,例如通过 ignore
。
更好的是,提取运算符返回cin
以便您可以在提取时进行测试:
if ( ! ( cin >> s >> n >> x >> s ) ) {
cout << "You fail horribly!n";
cin.clear();
cin.ignore( std::numeric_limits< std::streamsize >::max(), 'n' );
}
有关更深入的内容,请参阅basic_ios上的标志语义(我敢肯定,这个网站上有几个问题与此完全相同(。
尝试将错误的数据类型放在一起时遇到问题或异常。也许您想查看 cin 上>> 运算符的文档,查找有关它在数据类型输入错误时执行的操作的详细信息,并查看 cin>> 行和您的输入以查找可能发生这种情况的任何位置,以便您可以验证输入是否正确处理<</p>
当您调用 cin.clear(( 时, 你应该同时调用cin.sync((。
一旦流检测到错误,它就会处于错误状态,并且所有进一步尝试输入将是无操作。 访问由流而不首先测试读取是否成功是否未定义行为,所以至少在理论上,你的程序可以做任何事情。 (在实践,如果未初始化的变量是 char
类型,则您冒着所有风险是一个随机值。
读取面向行的输入时,最好的解决方案是使用 std::getline
.然后使用输入的字符串构造一个 std::istringstream
解析该行。 这会将输入流保留在良好的状态,并且已经同步用于下一个输入。 我会用像这样:
void
getInput()
{
std::string line;
std::cout << "Please type this: ABC456 7.8 9 XYZ" << std::endl;
std::getline( std::cin, line );
if ( ! std::cin ) {
// Very unexpected error...
throw SomethingSerious();
}
std::string s;
int n;
float f;
std::istringstream toParse( line );
toParse >> s >> f >> n >> s;
if ( ! toParse ) {
// Input incorrect...
}
}
bool
tryAgain()
{
std::cout << "Do you want to try again (y/n)? ";
std::string line;
std::getline( std::cin, line );
return line.size() == 1 && (line[0] == 'y' || line[0] == 'Y');
// But I'd be more tolerant with regards to spaces...
}
bool
oneInput()
{
getInput();
return tryAgain();
}
int
main()
{
while ( oneInput() ) {
}
return 0;
}
- boost::asio::io_service 在线程中,不会在应用程序退出时退出
- 当我选择大于 720 的矩阵大小时,程序退出并显示错误代码.可能是什么原因?
- thread_local静态类在程序退出时在无效地址处销毁
- OpenGL 应用程序退出,退出代码为 -1073741515 (0xC0000135)
- 程序退出后,将释放内存到系统
- 全局范围内的对象会导致程序退出时崩溃
- 不整洁的程序退出:MFC C
- 如果程序退出循环是goto已删除的本地变量
- Linux 阻止文件描述符在程序退出时关闭
- 为什么我的新分配指针会自动在程序退出上删除
- QFile在程序退出时保存文件,根本不会保存~500MB文件
- 类的静态实例无法在程序退出时正确处理资源删除
- 为什么全局或静态对象会导致程序退出时崩溃
- 由OpenCV 2.4.6创建的AVI文件在应用程序退出时并不总是有效
- C++DevIL函数ilLoadImage-程序退出,访问违规
- gdb程序退出了使用CMake的程序的代码01
- 问题5.1-QMessageBox错误?如果在QDialog隐藏时调用了QMessageBox,则程序退出(0)
- 多次调用函数会导致程序退出,并出现一个神秘的错误
- 如何在应用程序退出时诊断comptr版本中的异常
- C++-如何在程序退出时找到堆/堆栈损坏的源