【问题标题】:Is there a way to write such program without using goto?有没有办法在不使用 goto 的情况下编写这样的程序?
【发布时间】:2018-02-12 15:29:36
【问题描述】:

有没有办法不使用 goto 来编写这样的程序?如果有,怎么做?

【问题讨论】:

  • 一切皆有可能。
  • 你必须这样做
  • 那一连串的反对票和票数接近的理由让我感到困惑。这是一个明确的问题,答案实际上是。但我想简单地提到goto 就有这种效果。
  • 我同意昆汀关于结束问题的看法。不确定我是否同意答案是否定的 - 使用和不使用 goto 都会很混乱,并且取决于您认为 goto 有多“坏”,替代方案可能会更好。
  • 老实说,这看起来像是this question 的重复(轻微变体),并且接受的答案显示了如何使用递归来做到这一点。所以答案是是的它可以在没有goto的情况下完成。

标签: c++ algorithm goto flowchart


【解决方案1】:

这是众多潜在解决方案之一,您的编译器可以使其与使用 gotos 一样高效。

一个分支在 do/while 条件下处理。另一个分支由return 处理。

bool func();

int main()
{
     statement1();
     while( func() ) {}
     statement5();
}

bool func()
{
     statement2();
     do
     {
         statement3();
         if ( condition1() )
         {
             return true;
         }
         statement4();
     } while( condition2() )
     return false;
}

查看代码你可能会注意到逻辑相当复杂。

在实际程序中,这可能表明程序逻辑需要审查。

【讨论】:

    【解决方案2】:

    “有没有办法不使用 goto 来编写这样的程序?”
    ——菲利普·莫雷拉

    是的。从技术上讲,C++ 足够灵活,您可以禁止几乎任何一种构造,并且仍然能够实现您想要的,包括goto

    “如何”部分有点无趣,所以假设你会通过两个循环来做到这一点,在其中一个条件下使用额外的标志变量,这样它就不再像循环一样了,并且小心使用if 最终得到符合规范的东西。

    “是的,但是有没有办法自然地仅使用高级流控制来为这个流程图建模?”
    -- 有用的画外音

    没有。

    这实际上是 C++ 的高级构造不够用的典型案例之一。所有这些都是围绕嵌套范围的概念设计的(异常处理可以缩短范围,但仅此而已)。此流程图包含两个交叉循环,中间有足够的操作,您不能只是将它们打乱以获得嵌套循环。

    你有两个选择:

    • 只需使用goto。记录它,明确标签,并应用其他常见的良好做法。

    • 试着坚持“无goto”的规则来来回回​​,让其他控制结构变形,直到你有效地模拟了goto,附带一些流氓布尔值和棘手的条件.

    第二种解决方案最终可能比第一种更易读(他们说永远不要说“从不”),但你绝对不应该在尝试之前放弃第一个解决方案。

    作为参考,以下是您如何翻译流程图(按流程图中的顺序编号的操作和条件):

    action_one;
    
    properlyNamedLabel:
    action_two;
    
    do {
        action_three;
    
        if(condition_one)
            goto properlyNamedLabel;
    
        action_four;
    
    } while(condition_two);
    
    action_five;
    

    【讨论】:

      【解决方案3】:

      我认为没有人会尝试“按原样”制作此流程图 - 但可以进行一些修改。

      第一个循环显然是do {} while()。让我们现在将其提取到一个函数中,以使我们的生活更轻松。 第二个循环希望我们跳到 do while 的中间。好吧,而不是用 goto 做这个;调用我们的函数对我们来说更好;带有不做第一件事的标志。

      请注意,我使用流程图中的第二个任务作为我的第一个;因为它是循环中的第一个。

      因此你最终会得到类似的东西

      void myFirstLoopFunc(bool doFirstTask) {
          do {
              if (doFirstTask)
                  firstTask();
              doFirstTask = true;
              secondTask();
          }
          while(firstTest());
      }
      
      void mySecondLoopFunc() {
          bool doFirstThing = true;
          do {
              myFirstLoopFunc(doFirstThing);
              thirdTask();
              doFirstThing = false;
          } while (secondTest());
      }
      

      然后调用 mySecondLoopF​​unc 来启动链。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-11-29
        • 2019-07-23
        • 1970-01-01
        • 2013-09-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多