如何检查用户的输入是否有效? (C ++)

时间:2014-06-18 03:13:12

标签: c++ validation user-input infinite-loop cin

当谈到基于一组指令创建程序时,我在设计伪代码时做得很好,实现了实际的代码。我觉得我缺乏的是检查用户的输入(无论是有效还是无效)。当我练习编程时,我创建了自己的方法来检查验证用户的输入。但代码很长,我觉得它不够(我会解释原因)。我想知道是否有更好的方法来检查用户的输入。其他程序员如何实现他们的代码。

这是我验证用户输入的方式:

if(cin.fail()) {
        cout << "Invalid Input" << endl;
        cout << "Now Exiting..." << endl;
        return;
}
// I didn't know how to skip a line while in code
while(input < 0) {
        cout << "Invalid Input" << endl;
        cout << "Enter radius: " << endl;
        cin >> input;
        if(cin.fail()) {
             cout << "Error: Invalid Input" << endl;
             cout << "Now Exiting..." << endl;
             return;
        }
}

当cin无法将值单独存储到变量中时(第1-5行,第11行-15行)退出的原因是因为如果我将cin.fail()添加到while条件并尝试输入一封信,它开始无限循环。我做了一点研究,我看到你必须cin.sync(),然后cin.clear()。但我仍然得到无限循环。

以下是代码:

do {
        cin.sync()
        cin.clear();
        cout << "Enter radius: ";
        cin >> input;
} while(input < 0 || cin.fail());

如果我做错了什么,看看验证用户输入的更好方法会非常有帮助。

3 个答案:

答案 0 :(得分:1)

我不建议使用std :: cin,因为它会在输入缓冲区中第一个找到的空格实例后留下所有剩余的用户输入。除非使用cin.ignore()删除剩余的字符,否则会产生问题。通常认为使用getline()更好的做法是将所有字符都添加到换行符。如果您确实选择使用std :: cin,则需要使用cin.ignore()删除剩余的字符,并使用cin.clear()来重置cin的失败位,以便while条件可以正常工作下次循环。

以下是我如何解决问题。它使用getline()来获取所有字符,使用stringstream将字符串转换为int。请注意,您需要清除stringstream的失败位,就像使用cin一样,以确保在执行ss&gt;&gt;时条件正常工作。导致while条件。

std::cout << "Enter radius: ";
getline(std::cin, input);
std::stringstream ss(input);

while(!(ss >> result)) {
    std::cout << "Invalid Input" << std::endl;
    std::cout << "Enter radius: ";
    getline(std::cin, input);
    ss.clear();
    ss << input;
}

下面我还将包含一些使用std:cin解决问题的代码。我仍然建议使用getline()。注意:std :: numeric_limits :: max()用于指定要从输入缓冲区中删除的字符数。使用此代替您自己的任意数字是一种更好的做法,因为您无法确定用户将输入多少个字符。 cin.ignore()将删除所有给定数字的字符,或直到它到达作为第二个参数提供的字符实例,在这种情况下是换行符(&#39; \ n&#39;)。

std::cout << "Enter radius: ";
std::cin >> result;

while(std::cin.fail()) {
    std::cout << "Invalid Input" << std::endl;
    std::cout << "Enter radius: ";
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cin >> result;
}

答案 1 :(得分:1)

输入验证问题是一种简单的解析形式。

有一些语言类(在形式语言理论领域)表达了你输入的复杂性。这些类称为常规,无上下文和图灵完成。

您必须考虑所有可能的输入,您的程序可能会收到并决定您的程序是否应该接受它们。语言类可帮助您确定所需的输入验证类型。

如果语言是常规的(就像你的情况一样),你可以使用正则表达式来验证输入。

例如,无上下文的语言将是一个数学公式。您不能使用正则表达式计算括号的数量。因此,无法检查((a+b) * (c+d))是否具有正确表达式的正确数量的括号。

到目前为止,这些都是关于你应该做什么的提示,当你更自然地编程时。

为了简单起见,做一个非常有约束的正则表达式,比如手工解析。 你在伪代码中真正想做的事情:

do {
   std::cout << "Please enter radius: ";

   line = read_a_line_from(std::cin) // separated by '\n' the newline

   if (false == really_read_a_line(line)) {
      /* error handling for std::cin, dealing with i.e.: the fail bit */
      break; /* exit the loop */
   }
   if (line == "exit") { // give the user an explicit exit, to quit gracefully
      exit(SUCCESS); /* exit the program */
   }

   if (false == is_a_number(line)) {
      /* we read something that isn't a number */
      /* we should tell the user he should do as we asked */
      continue; /* jump back to the beginning of the loop */
   }

   unsigned num = convert_number(line);
   unsigned area = calculate_area(num); /* do something with your input */
} while (true);
exit(FAILURE);

这里的代码不是太具体,你可以看到你可以在某些地方做什么,但仍然没有实际的实现(为了你的练习)。请注意,通过转换检查线路实际上是否为数字的简单方法。但是,并非所有要解析的内容都应检查其有效性并同时处理。

另见(特别是例子):

http://en.cppreference.com/w/cpp/string/basic_string/getline

http://en.cppreference.com/w/cpp/string/basic_string/stol

how to check if given c++ string or char* contains only digits?

答案 2 :(得分:0)

do {
        cin.sync()
        cin.clear();
        cout << "Enter radius: ";
        cin >> input;
} while(input < 0 && cin.fail());