【问题标题】:c++ isalnum endless loopc++ isalnum无限循环
【发布时间】:2011-07-26 00:41:31
【问题描述】:

您好!

这次让我们删掉过多的介绍,直奔主题。

我在使用 isalnum 方法的 C++ 中遇到问题。

代码:

int playAgainst = 0;
do
{
    cout << "Who do you want to play against?(1/2)\n";
    cout << "1: Human player\n";
    cout << "2: Computer player\n";
    cin >> playAgainst
} while(!isalnum(playAgainst) && playAgainst != 0);

从代码中可以看出,我为用户提供了一个选择。与人类对战或与计算机对战。

我想要的是,只要用户输入其他任何内容,然后输入一个整数值(cin >> playAgainst)来重复问题。但是,如果我输入一个字符或字符串值,它会不断循环。我不是 100% 确定,但很明显,如果问题是,非 int 值已经保存为 playAgainst 的值。如果输入值是 int 在保存之前如何检查这段代码它?

或者是唯一的可能性保存为字符/字符串然后检查?

如果是后者,就会出现新的问题。 isalnum 只接受 int 作为参数,至少据我所知。我将如何检查该字符串或字符是否为 int?

感谢您抽出宝贵时间阅读。希望我能尽快接受答复^^

感谢大家的回答。 我得到了我想要的,一切都解决了。

我选择接受答案的原因很好......因为最初,它使我的代码按照我想要的方式工作。不过我想接受多个答案..

【问题讨论】:

    标签: c++ isnumeric


    【解决方案1】:

    playAgainst 设为char 并与'0' 进行比较,而不是0。现在,用户必须输入字符'1''2' 的ASCII(或任何你的字符集)代码。

    isalnum 不能在char 的有效范围之外的ints 上工作,EOF 除外。 (它接受int 参数的事实是C 的遗留物,它具有与C++ 不同的整数提升规则。 以适应EOF。)

    【讨论】:

    • while(playAgainst != '1' || playAgainst != '2') 这行得通。虽然它不完全是我所希望的。 (ex C#- er :P) 不过谢谢!在这种情况下,我害怕的是,如果我再添加 800 个选项(小说..)我必须写下 ||操作。在这种情况下,检查该值是否为数字,并且
    • 无论如何,您不能将 800 个值放入典型的 char 中。如果您确实想要int,那么isalnum 是没有用的。如果您不输入有效整数,cin &gt;&gt; i 将失败。
    • 这是一个虚构的问题,也许有点傻。这正是我担心的问题。该值必须是int。可以尝试一个 try-catch 块来解决这个问题。
    • @Joey 实际上这就是 isalnum 所做的。它只是检查 ASCII 值是否在某个区间 a-z 或 A-Z 或 0-9 内。就是这样,那里没有花哨的魔法。
    • @larsmans isalnum 接受一个 int 的事实不是 C 的遗留物(除了所有 都是 C 遗留物)。 isalnum 接受一个 int 以便它可以接受 EOF 以及一个字符。 (对于 EOF,它返回 false。)此外,C 和 C++ 的整数提升规则完全相同。也许你在想,'0' 在 C 中是一个 int,而在 C++ 中是一个 char。
    【解决方案2】:

    去掉isalnum() 勾选。 cin &gt;&gt; playAgainst 会将除数字之外的任何内容转换为零,这将被第二次检查捕获。请注意,这只是一个选项,因为零不是有效的输入。

    isalnum() 在您自己解释字符时很有用,但在这种情况下,流已经为您完成了。

    【讨论】:

    • 这是一个很好的答案。这确实有助于我澄清为什么会出现我的问题,谢谢。 :)
    【解决方案3】:

    这是编译器实现 isalnum 的方式:

    int isalnum (int ch)
    {
      return (ch >= 'a' && ch <= 'z') || 
             (ch >= 'A' && ch <= 'Z') || 
             (ch >= '0' && ch <= '9');
    }
    

    所以你不妨在自己的代码中编写该代码 sn-p,它与 isalnum 的内联版本等效。

    【讨论】:

    • 这并不能真正回答问题:为什么isalnum 在这种情况下不起作用?
    • 感谢您阐明 isalnum 的解释方式。知道总是有用的。然而,迈克·西摩是对的。不过没关系。我从所有答案中学到了很多东西!谢谢。
    • 确实,它没有回答问题,尽管它与澄清相关。如果 cmets 没有劣质的代码格式选项,我会将其作为评论发布。所以责怪 SO 网站。
    • 我还没有看到使用该解决方案的库。从历史上看,isalnum 是一个宏,它只引用了一次它的参数。类似(__ctype[(ch) + 1] &amp; M_ALNUM) != 0
    • @James 讽刺的是,这实际上是直接取自嵌入式系统编译器源代码。也许他们依靠他们的优化器使代码变得更漂亮。或者更有可能,他们只是不想分配查找表。实际上,我怀疑查找版本在速度方面是否会有任何显着改进,因为您必须执行数组索引、加法、AND 以及与零的比较。
    【解决方案4】:

    这是因为您没有清除缓冲区。当输入无效时,您需要将其从缓冲区中清除,然后您可以继续下一个输入,否则您每次都尝试提取相同的输入(失败,因为它是相同的错误输入),从而进入无限循环。

    【讨论】:

    • 这是一个很好的答案。非常感谢。我什至没有考虑清除缓冲区。唤醒耳光很受欢迎。
    【解决方案5】:

    问题是您输入的是 int,而不是 char。如果 输入中的文本不是 int,则输入失败。在这种情况下, playAgainst 没有被修改,并且失败被记忆在std::cin 直到您明确清除错误。并从一个流中输入 错误状态是无操作。你可能想要做的是

    1. 输入单个字符:如果您不想跳过空格,请使用 `std::cin.get(ch)` 或 `ch = std::cin.get()`。 (在后者 在这种情况下,`ch` 应该是 `int`,因为它还必须处理 `EOF`。 另一方面,您可以直接在其上使用`::isalnum`,这 如果 `ch` 是 `char`,则不能这样做。
    2. 全面检查有效输入:不仅仅是`::isalnum`,而是 输入是否是列表中的合法选择器。某物 沿着: ch != EOF && std::find( legalChars.begin(), legalChars.end(), (char)ch ) != legalChars.end()
    3. 如果出现错误,请清除所有剩余输入,例如: std::cin.ignore(INT_MAX, '\n');

    在实践中,您可能希望区别对待 EOF 一个错误的命令。 (如果EOF后面的输入不清除,你 将无法阅读其他任何内容。但是大概,如果你得到EOF, 是因为用户放弃了,不想再尝试了。)

    最后,最好将所有信息保存在 一个公共位置,使用以下表格:

    struct Command
    {
        char        op;
        char const* prompt;
        void (*     func)();
    };
    

    然后循环遍历这些表以输出提示,搜索到 看字符是否合法,最后调用函数 您找到的条目。或者定义一个抽象基类,一个具体类 从它为每个命令派生,并使用 std::map<char, AbstractBase*> 进行映射等。非常 C++,但可能有点 对于这样一个简单的案例来说太过分了。

    【讨论】:

      【解决方案6】:

      为什么不使用isdigit()

      【讨论】:

      • @Acme 不确定,但不管我改变与否,产生的结果都是一样的,但我知道区别,我应该使用 isdigit,因为我不需要检查上限/小写
      • @Joey Roosing :: 只需使用isdigit() 确保它是一个数字,然后根据您希望循环工作的方式测试&lt;1&gt;2
      • 并确保不要混淆数字和字符值;要使用isdigit(),您必须读取一个字符而不是整数,并与'1''2' 进行比较。
      • @Acme:我是。然而,这并不能解决我的问题。因为在代码示例中,我使用了 cin >> playAgainst,它决定了 playAgainst 的值,在我可以做检查之前,因为 isdigit(cin >> playAgainst) 会产生错误。它将无限循环,因为应该是 int 的值不是 int
      • @Mike Seymour:谢谢。确实是一个合乎逻辑的答案!我想拥有一个 char 是我真正想要完成的唯一解决方案。谢谢 :) 以及 Acme!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-27
      • 2015-04-29
      • 1970-01-01
      • 1970-01-01
      • 2013-02-22
      • 1970-01-01
      • 2012-02-27
      相关资源
      最近更新 更多