【问题标题】:How to catch invalid user inputs [closed]如何捕获无效的用户输入
【发布时间】:2019-02-01 06:10:34
【问题描述】:

我不理解 Try、throw、catch 语句,我想知道当你的代码中的所有输入都应该是 int 时,为什么捕获一个 char 是最好的。这是为了帮助阻止人们在我询问他们最喜欢的数字时变得愚蠢并打上“a”。这是我的代码示例,当我想要整数时,我试图防止有人输入字符:

int a, b;
std::cout << "Enter a Numerator: ";
std::cin >> a;
std::cout << "Enter a Denominator: ";
std::cin >> b;

【问题讨论】:

  • 究竟是为了保护什么?
  • 我会永远看到这个。用户键入字符和字符串,而不是整数。将输入读取为字符串并进行自己的验证。
  • 或更好地查看this
  • 谈到cin时,处理错误的最佳方法是if (!(std::cin &gt;&gt; a)),然后检查是否发生了不可恢复错误,例如eofbitbadbit 设置为 if (std::cin.eof() || std::cin.bad()) 或是否发生 可恢复 错误,例如failbit 已设置,检查 else if (std::cin.fail()) 之后可以调用 std::cin.clear(); 清除 failbit

标签: c++


【解决方案1】:

如果您合并两个问题(thisthis)的两个答案,我在您问题的 cmets 部分中提到,您会得到这个,

#include <iostream>

int main()
{
    int a, b;
    std::cout << "Enter a Numerator: ";
    std::cin >> a;
    std::cout << "Enter a Denominator: ";
    std::cin >> b;

    if (!std::cin.good())
    {
        throw std::invalid_argument( "received strings. Need integers" );
    }
}

正如第一个链接的答案所提到的,您可以参考here 以了解有关抛出哪些异常的更多信息。

正如第二个链接的答案所提到的,如果用户没有输入预期的正确数据类型,"cin 将切换它的故障位。将输入的数据类型更改为整数并检查此故障位将允许您验证用户输入。” .

作为事后的想法,您最好将分母也检查为零,在上面的代码示例中添加了类似的内容。

if (b /*assuming b is denominator*/ == 0) {
        throw std::overflow_error("Divide by zero exception");
}

【讨论】:

  • 谢谢你,这是一个巨大的帮助。我想我开始理解 try、throw 和 catch 命令了。我只是需要从不同的角度来看它。非常感谢。
  • 很高兴为您提供帮助。 :)
【解决方案2】:

要对输入例程进行更细粒度的控制,您需要学习使用std::ios_base::iostate 流状态goodbit, eofbit, badbit, and failbit。您可以使用std::basic_ios::rdstate 直接检查状态,也可以使用方便的成员函数.good(), .eof(), .bad() and .fail(),请参阅std::basic_istream

虽然检查.good() 会告诉您输入良好,但它并不能帮助您从失败的输入或错误条件或EOF 中恢复。为此,您必须单独检查发生的错误情况。

继续我的评论并添加一些细节,您可以执行以下操作(您只需对 ab 执行相同的操作 - 您可以移动到函数或成员函数),例如

#include <iostream>
#include <limits>

int main (void) {

    int a, b;

    /* get input for a */
    while (1)       /* loop continually reading input */
    {
        std::cout << "\nenter an integer for a: ";
        if (! (std::cin >> a) ) {   /* check stream state */
            /* if eof() or bad() break read loop */
            if (std::cin.eof() || std::cin.bad()) {
                std::cerr << "(user canceled or unreconverable error)\n";
                goto unrecoverable;
            }
            else if (std::cin.fail()) {     /* if failbit */
                std::cerr << "error: invalid input.\n";
                std::cin.clear();           /* clear failbit */
                /* extract any characters that remain unread */
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(),
                                '\n');
            }
        }
        else {  /* on succesful read, just output int and break loop */
            std::cout << "integer a: " << a << '\n';
            /* extract any characters that remain unread */
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(),
                            '\n');
            break;
        }
    }

    /* same thing for b */
    while (1)       /* loop continually reading input */
    {
        std::cout << "\nenter an integer for b: ";
        if (! (std::cin >> b) ) {   /* check stream state */
            /* if eof() or bad() break read loop */
            if (std::cin.eof() || std::cin.bad()) {
                std::cerr << "(user canceled or unreconverable error)\n";
                break;
            }
            else if (std::cin.fail()) {     /* if failbit */
                std::cerr << "error: invalid input.\n";
                std::cin.clear();           /* clear failbit */
                /* extract any characters that remain unread */
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(),
                                '\n');
            }
        }
        else {  /* on succesful read, just output int and break loop */
            std::cout << "integer b: " << b << '\n';
            /* extract any characters that remain unread */
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(),
                            '\n');
            break;
        }
    }

    unrecoverable:;
}

注意std::numeric_limits&lt;std::streamsize&gt;::max()std::cin.ignore 一起使用以清除stdin 中留下的任何违规字符。 (本质上提取字符的最大流大小,直到找到'\n')所以你下一次输入尝试不会尝试重新读取相同的错误字符并由于相同的原因再次失败 - 通常会导致无限如果输入是在循环中进行的,则循环。

还要注意使用旧的goto 以允许从程序中正常退出,无论用户是否取消ab 的输入。

这是一个输入例程,所以在你写完之后——去尝试打破它。如果它坏了,修复它。那是你可以捕捉到大多数极端情况的唯一方法,例如

使用/输出示例

$ ./bin/cin_validate_ab

enter an integer for a: no
error: invalid input.

enter an integer for a: OK
error: invalid input.

enter an integer for a: 5, I entered 5!
integer a: 5

enter an integer for b: again!
error: invalid input.

enter an integer for b: 6
integer b: 6

用户在 Linux 上使用 Ctrl+d(或在 Windows 上使用 Ctrl+z)取消输入。

$ ./bin/cin_validate_ab

enter an integer for a: (user canceled or unreconverable error)

检查一下,如果您有任何问题,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-02
    • 1970-01-01
    • 1970-01-01
    • 2022-07-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多