【问题标题】:Advanced switch statement within while loop?while循环中的高级switch语句?
【发布时间】:2023-03-03 22:38:01
【问题描述】:

我刚开始使用 C++,但对其他语言有一些先验知识(不幸的是,vb 不久前),但有一个奇怪的困境。我不喜欢使用这么多的 IF 语句,并且想使用 switch/cases,因为它看起来更干净,我想参与实践.. 但是..

假设我有以下场景(理论代码):

while(1) {

  //Loop can be conditional or 1, I use it alot, for example in my game
  char something;
  std::cout << "Enter something\n -->";
  std::cin  >> something;

  //Switch to read "something"
  switch(something) {
    case 'a':
      cout << "You entered A, which is correct";
      break;
    case 'b':
      cout << "...";
      break;
  }
}

这就是我的问题。假设我想退出 WHILE 循环,它需要两个 break 语句?

这显然看起来不对:

case 'a':
  cout << "You entered A, which is correct";
  break;
  break;

那么我可以只在'a'上做一个IF语句来使用break;吗?我错过了一些非常简单的东西吗?

这会解决我现在遇到的很多问题。

【问题讨论】:

  • 根据标题,我认为这可能是 Duff 的设备问题。没有。有boring标签吗?
  • 很高兴你的问题得到了解决,这些东西不是最好玩的。

标签: c++ logic switch-statement while-loop break


【解决方案1】:

我会将检查重构为另一个函数。

bool is_correct_answer(char input)
{
    switch(input)
    {
    case 'a':
        cout << "You entered A, which is correct";
        return true;
    case 'b':
        cout << "...";
        return false;
    }
    return false;
}

int main()
{
    char input;
    do
    {
        std::cout << "Enter something\n -->";
        std::cin  >> input;
    } while (!is_correct_answer(input));
}

【讨论】:

  • 其中一个函数需要修改以考虑大写或小写选择。
  • 只需将switch(input) 更改为switch(tolower(input))
【解决方案2】:

您可以简单地让 while 循环检查在您的一个 case 语句中设置的 bool 值。

bool done = false;    
while(!done)
{
 char something;
  std::cout << "Enter something\n -->";
  std::cin  >> something;

  //Switch to read "something"
  switch(something) {
    case 'a':
      cout << "You entered A, which is correct";
      done = true; // exit condition here
      break;
    case 'b':
      cout << "...";
      break;
  }
}

【讨论】:

  • 我想说这个答案有点不理想(但绝不是错误的)。如果在 switch 语句下添加代码,即使问题是直接退出外循环,它也会运行。如果(完成)中断,我会使用 Dimas;方法或 goto。
  • 是的,这是该解决方案的一个缺陷,代码在该开关下执行。在那里同意。
  • 有趣的我总是在(跑步)时使用
  • 你们都没有抓住重点。完成后执行的一些样板代码没有任何问题(例如重置计数器或任何其他杂项代码)。这不是一个陷阱,而是一个奖励。您必须跳出框框思考,看看在设置 done = true 后能够执行代码在哪里产生了积极影响。不是短路而是布尔值
【解决方案3】:

是的,C 和 C++ 没有办法说“退出多个可破坏块”(其中“可破坏块”是任何循环或开关)。解决方法包括gotos 和使用布尔变量来记录外部“可破坏块”是否也应该破坏(两者都不优雅,但这就是生活)。

【讨论】:

    【解决方案4】:

    两个break 语句不会让您退出while 循环。第一个break 只会让您脱离switch 语句,而第二个则永远不会到达。

    你需要做的是使while循环的条件为假,假设switch语句之后循环中没有任何内容。如果切换后还有其他代码,请检查switchbreak后面的条件。

    bool done = false; while(! done) { // do stuff switch(something) { case 'a': done = true; // exit the loop break; } // do this if you have other code besides the switch if(done) break; // gets you out of the while loop // do whatever needs to be done after the switch }

    【讨论】:

    • 如果你要检查 if (done),为什么不只做 while (true)。这是多余的。
    • 这取决于...您可能希望也可能不想在切换后立即中断。
    【解决方案5】:

    你可以试试:

    • 使用标志
    • 使用转到
    • 将 Inner Breakable 块放入函数中
    • 使用异常
    • 使用 longjump 和 setjmp

    与这个问题非常相似的话题

    http://www.gamedev.net/community/forums/topic.asp?topic_id=385116

    【讨论】:

    • 标记并将块包装到函数中。后藤不好。例外在这里根本不合适。退出循环不是错误。
    • Goto 还不错。我认为 goto 适合在这种情况下使用,标志也是如此。
    • 在我使用goto的示例代码中,如果switch语句后面有代码,它将保持整洁。
    【解决方案6】:

    您可能对 C++ 中的 named loop idiom 感兴趣。

    #define named(blockname) goto blockname; \
                             blockname##_skip: if (0) \
                             blockname:
    
    #define break(blockname) goto blockname##_skip;
    
    named(outer)
    while(1) {
    
      //Loop can be conditional or 1, I use it alot, for example in my game
      char something;
      std::cout << "Enter something\n -->";
      std::cin  >> something;
    
      //Switch to read "something"
      switch(something) {
        case 'a':
          cout << "You entered A, which is correct";
          break(outer);
        case 'b':
          cout << "...";
          break(outer);
      }
    }
    

    【讨论】:

      【解决方案7】:

      你也可以把循环封装成一个函数,在case里面调用return,以防flag破坏while不够用。 对于某些人来说,这不是一个好的编程习惯,但如果你保持函数简单,我不明白为什么不这样做。

      【讨论】:

        【解决方案8】:

        您可以用稍微过度设计的 OO 解决方案替换开关...

        #include <iostream>
        #include <map>
        #include <set>
        
        class input_responder
        {
            std::set<char> correct_inputs;
            std::map<char, const char*> wrong_inputs;
        
        public:
        
            input_responder()
            {
                correct_inputs.insert('a');
                wrong_inputs['b'] = "...";
            }
        
            bool respond(char input) const
            {
                if (correct_inputs.find(input) != correct_inputs.end())
                {
                    std::cout << "You entered " << input << ", which is correct\n";
                    return true;
                }
                else
                {
                    std::map<char, const char*>::const_iterator it = wrong_inputs.find(input);
                    if (it != wrong_inputs.end())
                    {
                        std::cout << it->second << '\n';
                    }
                    else
                    {
                        std::cout << "You entered " << input << ", which is wrong\n";
                    }
                    return false;
                }
            }
        };
        
        int main()
        {
            const input_responder responder;
            char input;
            do
            {
                std::cout << "Enter something\n -->";
                std::cin  >> input;
            } while (responder.respond(input) == false);
        }
        

        【讨论】:

          【解决方案9】:

          您可以将开关更改为 ifsystem。无论如何它都会被编译成同样的东西。

          【讨论】:

          • 好论据,如果没关系,我不介意稍微过于结构化的代码。 :P
          • 请务必添加注释来解释您使用if/else-if 的原因,以便您(或其他人)稍后看不到它并将其更改为更明显的 switch 语句,从而打破一切。没有双关语。
          • 如果有人重构了您的代码并且没有注意到他们已经改变了方法的基本行为,我不确定我是否会相信他们会首先阅读评论。跨度>
          • 它可能不会被编译成相同的东西。 switch 经常使用跳转表来实现,如果有很多 cases 可能会更快。
          • @Nick Lewis:我想大多数人都会注意到中断问题,就像@Jason 一样? @Thomas:我相信编译器也会使用跳转表,如果他们注意到 else if 中有一个简单的重复模式?
          猜你喜欢
          • 1970-01-01
          • 2013-12-20
          • 1970-01-01
          • 2013-04-13
          • 1970-01-01
          • 2018-09-16
          • 2022-01-03
          • 1970-01-01
          • 2023-04-10
          相关资源
          最近更新 更多