我的兄弟最近开始学习C++。他告诉我在尝试验证简单程序中的输入时遇到的问题。他有一个文本菜单,用户在其中输入了一个整数choice
,如果他们输入了无效的选项,则会要求他们再次输入它(do while循环)。但是,如果用户输入的是字符串而不是int,则代码将中断。
我阅读了关于stackoverflow的各种问题,并告诉他按照以下方式重写代码:
#include<iostream>
using namespace std;
int main()
{
int a;
do
{
cout<<"\nEnter a number:"
cin>>a;
if(cin.fail())
{
//Clear the fail state.
cin.clear();
//Ignore the rest of the wrong user input, till the end of the line.
cin.ignore(std::numeric_limits<std::streamsize>::max(),\
'\n');
}
}while(true);
return 0;
}
虽然这行得通,但我还尝试了其他一些想法:
1.使用try catch块。没用我认为这是因为输入错误导致未引发异常。
2.我尝试了
if(! cin){//Do Something}
,它也不起作用。我还没有想到这一点。3.第三,我尝试输入固定长度的字符串,然后解析它。我会使用atoi()。该标准是否合规且可移植?我应该编写自己的解析函数吗?
4.如果编写一个使用cin的类,但是可以通过在运行时确定输入变量的类型来动态地进行这种错误检测,会不会有太多的开销?可能吗?
我想知道进行这种检查的最佳方法是什么,最佳实践是什么?
我想补充一点,尽管我不是刚开始编写C++代码,但还是刚开始编写符合标准的代码。我正在尝试学习不良做法并学习正确的做法。如果回答者给出详细的解释,我将非常有义务。
编辑:我看到litb回答了我以前的编辑之一。我将在此处发布该代码以供引用。
#include<iostream>
using namespace std;
int main()
{
int a;
bool inputCompletionFlag = true;
do
{
cout<<"\nEnter a number:"
cin>>a;
if(cin.fail())
{
//Clear the fail state.
cin.clear();
//Ignore the rest of the wrong user input, till the end of the line.
cin.ignore(std::numeric_limits<std::streamsize>::max(),\
'\n');
}
else
{
inputCompletionFlag = false;
}
}while(!inputCompletionFlag);
return 0;
}
该代码在输入“1asdsdf”时失败。我不知道该如何解决,但是litb发布了一个不错的答案。 :)
最佳答案
这是您可以用来确保您也拒绝类似的代码
42crap
数字后面是非数字字符。如果您读了整行然后解析并适本地执行操作,则可能需要您更改程序的工作方式。如果您的程序到现在为止都是从其他地方读取您的电话号码,那么您必须将一个中央位置放在解析一行输入的内容上,然后决定要执行的操作。但这也许也是一件好事-因此,您可以通过将内容分开来提高代码的可读性: I nput- P 处理- O utput
无论如何,这是您如何拒绝上述数字为非数字的方法。将一行读取为字符串,然后使用
stringstream
对其进行解析:std::string getline() {
std::string str;
std::getline(std::cin, str);
return str;
}
int choice;
std::istringstream iss(getline());
iss >> choice >> std::ws;
if(iss.fail() || !iss.eof()) {
// handle failure
}
它会吃掉所有尾随的空格。当它在读取整数或尾随空白时到达字符串流的文件末尾时,便设置了eof位,然后我们进行检查。如果它首先无法读取任何整数,则将设置失败或错误位。
此答案的早期版本直接使用
std::cin
-但是std::ws
与与连接到终端的std::cin
一起使用时效果不佳(它会阻止用户等待输入内容),因此我们使用stringstream
读取整数。回答您的一些问题:
问题: 1.使用try catch块。没用我认为这是因为输入错误导致未引发异常。
答案:好吧,当您阅读某些内容时,您可以告诉流抛出异常。您使用
istream::exceptions
函数,该函数告诉您要引发异常的错误类型:iss.exceptions(ios_base::failbit);
我从来没有使用过。如果在
std::cin
上执行此操作,则必须记住为依赖它而不抛出的其他读取器恢复标志。发现仅使用函数更容易失败,很难询问流的状态。问题: 2.我尝试了不起作用的
if(!cin){ //Do Something }
。我还没有想到这一点。答案:这可能是由于您给了它“42crap”之类的东西。对于流,将其提取为整数时,这是完全有效的输入。
问题: 3.第三,我尝试输入固定长度的字符串,然后对其进行解析。我会使用atoi()。该标准是否合规且可移植?我应该编写自己的解析函数吗?
答案: atoi符合标准。但是,当您要检查错误时,这不是很好。与其他功能相比,它没有错误检查。如果您有一个字符串,并且想要检查它是否包含数字,则可以像上面的初始代码中那样进行操作。
有一些类似于C的函数可以直接从C字符串读取。它们的存在是为了允许与旧的旧代码交互以及编写快速执行的代码。人们应该在程序中避免使用它们,因为它们的工作级别较低,并且需要使用原始的裸指针。就其本质而言,它们也不能增强为与用户定义的类型一起使用。具体来说,这里讨论的是函数“strtol”(字符串到长整数),该函数基本上是atoi,具有错误检查功能以及与其他库(例如hex)一起工作的能力。
问题: 4.如果我编写一个使用cin的类,但是可以通过在运行时确定输入变量的类型来动态地进行这种错误检测,是否会有太多的开销?可能吗?
答案:通常,您在这里不需要过多地关注开销(如果您是指运行时开销)。但这具体取决于您在哪里使用该类。如果您要编写一个高性能的系统来处理输入并需要始终保持较高水平,那么这个问题将非常重要。但是,如果您需要从终端或文件中读取输入,那么您已经知道这可以归结为:WAITING用户输入某些内容确实花费了很长时间,因此您现在就不必再为此花费时间了。规模。
如果您指的是代码开销,那么这取决于代码的实现方式。您将需要扫描读取的字符串-它是否包含数字,是否包含任意字符串。根据您要扫描的内容(也许还有“日期”输入或“时间”输入格式。为此,请查看
boost.date_time
),您的代码可能会变得任意复杂。对于简单的事情,例如是否在数字之间进行分类,我认为您可以省去少量的代码。
关于c++ - 使用cin在C++中进行输入验证的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/545907/