为什么’continue’语句忽略’while’循环中的循环计数器增量,而不是’for’循环?

如果我在while循环中使用continue ,为什么它会进入无限循环,但在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 ... } 

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

有了这些, i++只是循环体中的另一个陈述(与a = b没什么不同),如果你在到达它之前continue ,就会跳过。

原因是continue语句会使循环体中跟随它的语句短路。 由于你编写while循环的方式在continue语句后面有increment语句,因此它会被短路。 您可以通过更改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 。 后一替代方案仅在迭代完成后执行增量,就像(前者在迭代之前执行增量,延迟将其保存在i直到迭代之后)。

你的增量是在继续之后,所以它永远不会被执行

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

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

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

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

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

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

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

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

如果满足循环的条件,则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可能certificate是有利的; 但是,应该注意:如果在这样的实现之后修改代码,则必须记住更新语句的两个实例(这可能容易出错,特别是如果修改发生在一段延长的时间之后** )。 因此,我高度推荐解决方案#2。

*有些人考虑使用goto不良做法。 我建议你自己决定,然后离开你: google for“c goto bad”

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

没有理由对单行进行评论

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