使用cin要求int时,如何有效地确保用户输入的安全性?

时间:2018-09-12 00:36:43

标签: c++ visual-c++ cin

这是我在这里的第一篇文章,对编程/ C ++我是一个新手(从字面上来说,这只是短短几个星期)。我已经在Microsoft Visual Studio 2017中建立了这个测试项目,并且试图找出如何在使用cin时完全实现用户输入的万无一失。如果我要的是整数,而我只想要1或0,则我绝对不希望有人将数字放在2或n之类的地方,或者将错误和正确的响应之间的空格“ n 1”。目前,我已经达到了这样一个程度,我似乎可以创建不希望的结果的唯一方法是,如果我先输入正确的整数(0或1),然后在其后跟一个空格和任何其他字符,然后使用此模式可以在初始正确的空格(0 a 42 f 9130)之后加上无限数量的空格和字符,等等。除了只是获得了更加混乱的代码所期望的结果外,我想知道我是否只是缺少一些-内置的函数,这些函数使我可以更高效地进行处理,而我还没有听说过。这是我为达到这一点而写的:

#include <iostream>
#include <string>
#include <climits>

using namespace std;

int trap;
int wrongNumber();

int numOnly() {
    while (cin.fail())
    {
        // Using someone else's code for this while statement to figure out how to not take a char input when using an int
        // Update: Turned this into a function to be called on whenever cin has a chance to fail because users don't listen.

        cin.clear(); // clear input buffer to restore cin to a usable state
        cin.ignore(INT_MAX, '\n'); // ignore last input
        system("CLS");
        cout << "----------------------------------" << endl;
        cout << "|  You can only enter a number.  |" << endl;
        cout << "| Would you like to pick a card? |" << endl;
        cout << "|  Type 1 for yes or 0 for no!   |" << endl;
        cout << "----------------------------------" << endl;
        cin >> trap;
    }
    if (trap != 1 && trap != 0) {
        system("CLS");
        wrongNumber();
    }
    return trap;
}

int wrongNumber() {

    // At least I made this fail-safe on my own!

    while (trap != 1 && trap != 0) {
        system("CLS");
        cout << "----------------------------------" << endl;
        cout << "|    That is not a 1 or a 0!     |" << endl;
        cout << "| Would you like to pick a card? |" << endl;
        cout << "|   Type 1 for yes or 0 for no!  |" << endl;
        cout << "----------------------------------" << endl;
        cin >> trap;
    }
    if (cin.fail()) {
        system("CLS");
        numOnly();
    }
    return trap;
}

int main() {

    cout << "----------------------------------" << endl;
    cout << "| Would you like to pick a card? |" << endl;
    cout << "|   Type 1 for yes or 0 for no!  |" << endl;
    cout << "----------------------------------" << endl;
    cin >> trap;

    while (cin.fail())
    {
        numOnly();
    }

    if (trap != 1 && trap != 0) {
        wrongNumber();
    }

5 个答案:

答案 0 :(得分:1)

我建议您不要使用整数来存储“是”或“否”答案,而应使用字符串代替。这样,您可以使用cin.fail()cin.ignore()cin.clear()保存一些代码行:

 int main() {

    string trap;
    cout << "----------------------------------" << endl;
    cout << "| Would you like to pick a card? |" << endl;
    cout << "|   Type 1 for yes or 0 for no!  |" << endl;
    cout << "----------------------------------" << endl;
        cin>>trap;

        while (trap != "1" && trap != "0") { //You can make this while block into a function if you prefer
            cout << "----------------------------------" << endl;
            cout << "|    That is not a 1 or a 0!     |" << endl;
            cout << "| Would you like to pick a card? |" << endl;
            cout << "|   Type 1 for yes or 0 for no!  |" << endl;
            cout << "----------------------------------" << endl;
                cin>>trap;
        }
    return 0;
}

如果 必须 使用整数,则应查看thiscapturing characters without pressing enter

答案 1 :(得分:0)

最好的方法是不依赖某些操作系统功能:

#include <iostream>
#include <limits> // std::numeric_limits
#include <cctype> // std::isspace

// function to read and discard whitespace except '\n' from a stream
std::istream& eat_whitespace(std::istream &is)
{
    char ch;

    // as long as the next character in the stream is a space and not a newline
    while (std::isspace(ch = is.peek()) && ch != '\n') 
        is.get(); // get and discard the character

    return is;
}

int read_range_strict(std::istream &is, int min, int max)
{
    int value;

    // as long as
    while (!(is >> value >> eat_whitespace) // extraction of an int fails
           || is.peek() != '\n' // or the next character in the stream is not a newline *)
           || value < min || max < value // or the value is not within the specified range
    ) {

        std::cerr << "Please enter a number between " << min << " and " << max << "!\n\n";
        is.clear(); // clear flags
        // discard everything that might be left in the stream
        is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }

    return value;
}

int main()
{
    int value;
    do {
        value = read_range_strict(std::cin, 0, 1);
    } while (true); // only for demo
}

*),我们尝试使用eat_whitespace建立。因此,如果流中还剩下不是\n的内容,我们就会在数字之后得到一些垃圾。

答案 2 :(得分:0)

由于唯一的有效值为0和1,因此您无需将输入读取为int值。只需将其读取为字符串,修剪所有空格并将字符串与“ 0”或“ 1”进行比较即可。

当然,您也可以只接受“ y”或“ n”,这将对用户更加友好。

答案 3 :(得分:0)

作为回答状态之一,更容易将输入读取为字符串,然后对该字符串求值。这是一个示例:

#include <iostream>
#include <string>

int main() {
  std::string trap;

  std::cout << "Enter 1 or 0" << std::endl;
  std::getline(std::cin, trap); // fetch user input, save into trap
  while (std::cin.fail() || (trap != "1" && trap != "0")) {
    std::cout << "That was not a 1 or 0; try again" << std::endl;
    std::getline(std::cin, trap);
  }
  return 0;
}

此代码读取所有用户输入,确定它是1还是0,然后成功退出或根据用户输入的内容提示用户。

如果我的理解正确,那么类似的事情可能会帮助您实现万无一失的用户输入。我建议您将代码修改为类似的代码,而不要使用多个函数来执行类似的任务。

答案 4 :(得分:0)

根据您的编译器,您可以使用诸如getch()之类的C代码,并且仅在执行检查后将其回显到屏幕上。然后,您必须按char来获取代码char并显然要汇编您的字符串。

https://www.c-lang.thiyagaraaj.com/archive/c-blog/use-of-getch-getche-and-getchar-in-c

免责声明:并非所有C ++编译器都支持此功能。这是C代码,而不是C ++。