【问题标题】:Why is 'continue' statement ignoring the loop counter increment in 'while' loop, but not in 'for' loop?为什么'continue'语句忽略'while'循环中的循环计数器增量,而不是'for'循环?
【发布时间】:2013-05-11 23:35:40
【问题描述】:

如果我在while 循环中使用continue,为什么它倾向于进入无限循环,但在for 循环中工作正常?
如果我在continue 之后使用循环计数器增量i++,它会在while 循环中被忽略,但如果它在for 循环中,它会起作用。

如果continue 忽略后续 语句,那么为什么不忽略for 循环的第三条语句,其中包含计数器增量i++for 循环的第三条语句 subsequentcontinue 是否也应该被忽略,因为for 循环的第三条语句是在 之后执行的循环体?

while(i<10)   //causes infinite loop
{
    ...
    continue
    i++
    ...
}

for(i=0;i<10;i++)  //works fine and exits after 10 iterations
{
    ...
    continue
    ...
}

【问题讨论】:

  • 查看输出程序集,您会发现 for 循环并没有像您想象的那样扩展。
  • 问:如果将continue AFTER i++ 放入“while”循环会发生什么?问:你明白初始化、增量和条件都是你的“for”循环中同一个结构的一部分吗?它们总是被执行,与循环内发生的事情无关?
  • Thokchom,我建议你找一些比 MS 提供的更好的文档 :-)
  • MS 是信任的代名词?我拒绝发表评论 :-) 无论是错误的还是被误解的,我都会留给你决定。它确实将控制权传递回for主体的第一条语句,但在首先执行后期操作之后。
  • Thokchom,我认为这是一个错字,条件表达式是中间那个,所以我怀疑他们的意思是“......导致 for 语句的 third 表达式待评估”。

标签: c loops for-loop while-loop continue


【解决方案1】:

因为continue 回到循环的开头。使用for,后操作i++是循环控制的一个整体部分,在循环体重新启动之前执行。

对于whilei++ 只是循环体中的另一个语句(与a = b 之类的语句没有什么不同),如果您在到达之前continue 将被跳过。

【讨论】:

  • 我死定了!!微软网站还有一个自相矛盾的描述。上面写着A continue statement in a for statement causes the first expression of the for statement to be evaluated--msdn.microsoft.com/en-IN/library/0ceyyskb(v=vs.80).aspx你能解释一下控制权是如何进入for循环的第一条语句的吗?
  • @Thokchom,鉴于该页面上指向for 声明的链接甚至没有描述第三部分(操作后),我将依靠其他东西来学习.
  • @Thokchom 该页面上的描述严重损坏。他们为明确描述for 声明的页面提供的链接是准确的。您可能需要考虑提交更正请求。
  • @NikBougalis 不敢相信微软网站会如此不专业。
  • @Thokchom 放松,错误发生了。尤其是当您必须维护一个内容与 MSDN 一样多的网站时。
【解决方案2】:

原因是continue 语句会短路循环体中跟在它后面的语句。由于您编写while 循环的方式在continue 语句之后有增量语句,因此它会短路。您可以通过更改 while 循环来解决此问题。

很多教科书声称:

for (i = 0; i < N; ++i) {
    /*...*/
}

相当于:

i = 0;
while (i < N) {
    /*...*/
    ++i;
}

但是,实际上,真的是这样的:

j = 0;
while ((i = j++) < N) {
    /*...*/
}

或者,更迂腐一点:

i = 0;
if (i < 10) do {
    /*...*/
} while (++i, (i < 10));

这些更等效,因为现在如果while 的主体有一个continue,增量仍然会发生,就像在for 中一样。后一种选择只在迭代完成后执行增量,就像for 一样(前者在迭代之前执行增量,推迟到迭代之后将其保存在i 中)。

【讨论】:

  • @Thokchom:不同之处在于,最后一个公式将允许while 循环中的continue 继续递增。
  • 哦..当一个人想要continue 不要忽略增量时会很方便。好技巧! +1
  • @Thokchom:谢谢,我更新了答案,让我的意图更加清晰。
【解决方案3】:

i 的增量是在 continue 之后,所以它永远不会被执行

while(i<10)   //causes infinite loop
{
.........
continue
i++
......
}

【讨论】:

    【解决方案4】:

    在任何循环中,continue 将执行移回循环顶部,在 continue 语句之后不执行任何其他指令

    在这种情况下,总是执行 for 循环的定义(根据标准 C),而 i++;语句未执行,因为它出现在 continue 语句之后。

    【讨论】:

      【解决方案5】:

      因为 for 的第三部分总是被执行。

      【讨论】:

      • 这个答案应该在字典中的“重言式”下链接。
      【解决方案6】:

      continue 语句将控制跳转到循环当前迭代中的语句末尾,即它跳过当前迭代中语句的执行并移动到循环的下一个迭代。

      使用while 循环,continue 语句会导致控制到达语句的末尾(包括增量语句),从而导致循环永远继续。

      使用for 循环,continue 语句将控制跳转到语句末尾并执行增量语句(在for 循环中,增量语句被认为与循环体中编写的语句是分开的)。

      【讨论】:

        【解决方案7】:

        for 循环包含条件语句和增量,因此当条件满足时,它会执行 for 循环内的语句,但如果编写 continue 语句,它将再次到达 for 循环的第一行,即增量和条件语句检查,如果满意,则再次执行。 对于 while 循环,它只检查条件语句,如果条件满足,则执行 while 循环中的语句。 所以 continue 不会在它之后执行任何行。因此你的条件每次都满足并进入无限循环。

        【讨论】:

          【解决方案8】:

          continue 绕过块的其余部分,如果满足循环的条件,则从块的顶部重新开始。

          下一个问题是:“那我该怎么办?” 我能想到的答案有两个。

          例子:

          void foo ()
          {
              size_t i = 0;
              do
              {
                  /*...*/
                  if ( /*...*/ )
                  {
                      /*...*/
                      continue;
                  }
                  /*...*/
                  i++;
              } while ( /* loop conditional */ );
          }
          

          解决方案 #1: 手动递增

          void foo ()
          {
              size_t i = 0;
              do
              {
                  /*...*/
                  if ( /*...*/ )
                  {
                      /*...*/
                      i++;
                      continue;
                  }
                  /*...*/
                  i++;
              } while ( /* loop conditional */ );
          }
          

          解决方案 #2:goto* 的唯一有效应用程序

          void foo ()
          {
              size_t i = 0;
              do
              {
                  /*...*/
                  if ( /*...*/ )
                  {
                      /*...*/
                      goto foo_next;
                  }
                  /*...*/
          foo_next:
                  i++;
              } while ( /* loop conditional */ );
          }
          

          goto 在这种情况下是有效的,因为在两个地方的递增在技术上是相同的指令。当 per-iteration-volatile 变量更复杂时,此解决方案尤其重要;例如,设置多个变量或使用方程式或函数修改值。

          在单个递增或递减语句的情况下,解决方案 #1 可能证明是有利的;但是,应该注意的是:如果在这样的实现之后修改了代码,必须记住更新语句的两个实例(这可能容易出现错误,特别是如果修改发生在很长一段时间后** )。因此,我强烈推荐解决方案 #2。

          *有些人认为任何和所有使用goto 都是不好的做法。我建议您自己决定,并留给您:google for "c goto bad"

          **一条提醒这种必要性的评论可能就足够了,但是——如果我的建议被遵循——每迭代易失性变量被限制在一个语句中。我引用:

          从不评论一行

          -Linus Torvalds(来源:http://yarchive.net/comp/linux/coding_style.html

          【讨论】:

            猜你喜欢
            • 2015-12-13
            • 1970-01-01
            • 2016-10-07
            • 2017-04-29
            • 2011-04-21
            • 2013-08-26
            • 1970-01-01
            • 1970-01-01
            • 2017-06-08
            相关资源
            最近更新 更多