bat*_*rat 8 c++ validation coding-style
我哥哥最近开始学习C++.他告诉我在尝试在简单程序中验证输入时遇到的问题.他有一个文本菜单,用户输入一个整数choice
,如果他们输入了无效的选项,他们会被要求再次输入(循环时).但是,如果用户输入的是字符串而不是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;
}
Run Code Online (Sandbox Code Playgroud)
虽然这个工作正常,但我还尝试了其他一些想法:
1.使用try catch块.它没用.我认为这是因为输入错误不会引发异常.我试过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;
}
Run Code Online (Sandbox Code Playgroud)
此代码在输入失败,如"1asdsdf".我不知道如何修复它,但litb发布了一个很好的答案.:)
Joh*_*itb 17
这是您可以使用的代码,以确保您也拒绝这样的事情
42crap
Run Code Online (Sandbox Code Playgroud)
其中非数字字符跟随数字.如果您阅读整行,然后解析它并适当地执行操作,则可能需要您更改程序的工作方式.如果您的程序从不同的地方读取您的号码,那么您必须放置一个解析一行输入的中心位置,并决定该操作.但也许这是一件好事-这样你就可以通过分离有东西增加代码的可读性这样:我 NPUT - P rocessing - Ø本安输出
无论如何,这里是你如何拒绝上面的数字 - 非数字.将一行读入一个字符串,然后用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
}
Run Code Online (Sandbox Code Playgroud)
它吃掉所有尾随的空白.当它在读取整数或尾随空格时命中字符串流的文件结尾时,它会设置eof-bit,然后检查它.如果它首先无法读取任何整数,那么将设置失败或坏位.
这个答案的早期版本std::cin
直接使用- 但连接到终端std::ws
时不能很好地工作std::cin
(它会阻塞而不是等待用户输入内容),所以我们用a stringstream
来读取整数.
回答你的一些问题:
问题: 1.使用try catch块.它没用.我认为这是因为输入错误不会引发异常.
答:嗯,你可以告诉流你在读东西时抛出异常.您可以使用该istream::exceptions
函数来确定要抛出异常的错误类型:
iss.exceptions(ios_base::failbit);
Run Code Online (Sandbox Code Playgroud)
我从来没用过它.如果你这样做std::cin
,你将不得不记住恢复依赖它而不是投掷的其他读者的标志.找到方法更容易使用函数失败,不好要求流的状态.
问题: 2.我试过if(!cin){ //Do Something }
哪个也没用.我还没想出来.
答:这可能来自于你给它类似"42crap"的事实.对于流,在提取整数时,这是完全有效的输入.
问题: 3.第三,我尝试输入固定长度的字符串然后解析它.我会用atoi().这个标准是否合规且便携?我应该编写自己的解析函数吗?
答: atoi符合标准.但是当你想要检查错误时,它并不好.没有错误检查,由它完成,而不是其他功能.如果你有一个字符串,并想检查它是否包含一个数字,那么就像在上面的初始代码中那样做.
有类似C的函数可以直接从C字符串中读取.它们的存在是为了允许与旧的遗留代码进行交互并编写快速执行的代码.人们应该在程序中避免它们,因为它们的工作水平较低,需要使用原始的裸指针.就其本质而言,它们无法增强以使用用户定义的类型.具体来说,这谈到了函数"strtol"(字符串到长),它基本上是atoi,具有错误检查和与其他基础(例如十六进制)一起工作的能力.
问题: 4.如果我编写了一个使用cin的类,但是动态地执行这种错误检测,也许通过在运行时确定输入变量的类型,它会有太多的开销吗?它甚至可能吗?
答:通常,您不需要过多关注开销(如果您的意思是运行时开销).但它具体取决于您使用该类的位置.如果您正在编写一个处理输入并且需要高整数的高性能系统,那么这个问题将非常重要.但是如果你需要从终端或文件中读取输入,你已经看到了这一点:等待用户输入的东西需要很长时间,你现在不需要再看这个时候的运行时成本规模.
如果你的意思是代码开销 - 那么它取决于代码的实现方式.您需要扫描您读取的字符串 - 是否包含数字,是否包含任意字符串.根据您要扫描的内容(也许您有"日期"输入或"时间"输入格式.请查看boost.date_time
),您的代码可能会变得任意复杂.对于简单的事情,比如在数字与否之间进行分类,我认为你可以通过少量的代码来逃避.