为什么在'while'循环中'continue'语句会忽略循环计数器的增量,但在'for'循环中不会?

13
为什么在while循环中使用continue会倾向于进入无限循环,但在for循环中却可以正常工作?如果我在continue之后使用i++来增加循环计数器,在while循环中它会被忽略,但在for循环中它可以正常工作。
如果continue忽略随后的语句,则为什么不忽略for循环的第三个语句,其中包含计数器增量i++for循环的第三个语句也是随后的语句,应该被忽略,因为for 循环的第三个语句在循环体之后执行吗?
while(i<10)   //causes infinite loop
{
    ...
    continue
    i++
    ...
}

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

3
Q: 如果在“while”循环中将continue放在i++后面会发生什么? Q: 你明白在“for”循环中初始化、增量和条件都是同一结构的一部分吗? 它们总是独立于循环内发生的事情而执行吗? - paulsm4
问:但是 for 循环的第三个语句不是每次都在循环体之后执行吗? 答:是的。 问:...continue 预期会忽略它后面的所有内容吗? 答:不是 :) - paulsm4
1
Thokchom,我建议你找一些比微软提供的更好的文档 :-) - paxdiablo
1
微软是否代表着信任?我拒绝发表评论 :-) 它是对还是被误解了,我将留给你来决定。它确实将控制权传递回for循环体的第一条语句,但仅在先执行后操作内容之后。 - paxdiablo
2
Thokchom,我认为那是一个打字错误,条件表达式是中间的那个,所以我怀疑他们的意思是“...导致for语句的第三个表达式被评估”。 - paxdiablo
显示剩余9条评论
8个回答

29
因为continue返回到循环的开头。在for中,后置操作i++是循环控制的一个整体部分,并在循环主体重新启动之前执行。
while中,i++只是循环主体中的另一个语句(与a = b之类的语句没有区别),如果在达到它之前使用continue,则会被跳过。

我要死了!!微软网站上有另一个矛盾的描述。它说for语句中的continue语句会导致for语句的第一个表达式被评估--http://msdn.microsoft.com/en-IN/library/0ceyyskb(v=vs.80).aspx 您能解释一下控制如何转向for循环的第一个语句吗? - Thokchom
@Thokchom,鉴于该页面上指向“for”语句的链接甚至没有描述第三部分(后操作),我将依靠其他东西来学习。 - paxdiablo
@Thokchom,该页面的描述非常混乱。他们提供的链接到明确描述“for”语句的页面是准确的。您可能需要考虑提交更正请求。 - Nik Bougalis
@NikBougalis 无法相信微软的网站会如此不专业。 - Thokchom
@Thokchom 放松,犯错误是很正常的。特别是当你需要维护像 MSDN 这样拥有大量内容的网站时。 - Nik Bougalis
@Thokchom:昨天我们遇到了一个问题,IBM AIX上的C编译器文档同样是虚假的。不要依赖厂商文档。阅读C标准或一本权威的C书籍。 - R.. GitHub STOP HELPING ICE

11

原因是因为 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继续递增。 - jxh
哦,当一个人想让 continue 不忽略增量时,这将非常方便。好技巧!+1 - Thokchom
@Thokchom:谢谢,我更新了答案以使我的意图更加清晰。 - jxh

3

i的增量在continue之后,因此它永远不会执行

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

2
在任何循环中,continue语句将执行返回到循环的顶部,不会执行在continue语句后面的其他指令
在这种情况下,for循环的定义始终被执行(根据标准C),而i ++;语句不会被执行,因为它位于continue语句之后。

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搜索“c goto bad”

**一个提醒这个必要性的注释可能足够了,但是-如果我的建议被采纳-每次迭代的易变变量都限制在一个语句中。我引用:

"永远没有理由注释单行代码" - Linus Torvalds(来源:http://yarchive.net/comp/linux/coding_style.html

0

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


这个答案应该被链接到“同义反复”的词条下。 - zubergu

0

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

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

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


0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接