为什么'继续'语句忽略循环计数器增量'而'循环,但不是'对于'环?

时间:2013-05-16 22:02:25

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

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

如果continue忽略后续语句,那么为什么它不会忽略for循环的第三个语句,其中包含计数器增量i++ ?不是for循环后续continue的第三个语句,并且应该被忽略,因为执行了for循环的第三个语句循环体之后?

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

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

8 个答案:

答案 0 :(得分:23)

因为continue回到循环的开头。对于for,操作后i++是循环控件的积分部分,并在循环体重新启动之前执行。

使用whilei++只是循环体中的另一个语句(与a = b没有区别),如果你continue之前跳过了{{1}}到达它。

答案 1 :(得分:10)

原因是因为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中直到迭代之后)。

答案 2 :(得分:3)

i的增量在继续之后,因此永远不会被执行

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

答案 3 :(得分:2)

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

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

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

使用for循环,continue语句将控件跳转到语句的结尾并执行递增语句(在for循环中,递增语句被认为与在正文中写入的语句分开循环)。

答案 6 :(得分:0)

for循环保存条件语句和递增,所以当条件满足时,它继续执行for循环中的语句,但是如果写继续语句,它将再次到达for循环的第一行,即增加和检查条件语句,如果满意再次进来执行。 对于while循环,它只检查条件语句,如果条件满足,它将在while循环中执行语句。 所以继续不会在它之后执行任何行。因此你的条件每次都满足并且进入无限循环。

答案 7 :(得分:0)

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在这种情况下有效,因为两个地方的增量在技术上是相同的指令。当每次迭代 - 易变量变量更复杂时,此解决方案尤其重要;例如,设置多个变量或用等式或函数修改值。

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

*有些人会考虑使用goto不良做法。我建议你自己决定,并留下这个:google for "c goto bad"

**提醒这种必要性的评论可能就足够了,但是 - 如果我的建议已被遵循 - 每次迭代 - 易变变量仅限于一个语句。我引述:

  

从不是评论单行的理由

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