66

可能的重复:
使用 for 循环或 while 循环进行迭代?
C 中的循环 - for() 或 while() - 哪个是最好的?

什么时候应该使用for循环而不是while循环?

我认为以下循环是相同的,除了它们的语法。如果是这样,那为什么选择一个而不是另一个?

int i;
for (i = 0; i < arr.length; i++) {
  // do work
}

int i = 0;
while (i < arr.length) {
  // do work
  i++;
}
4

28 回答 28

104

for在您的情况下,除了循环中少一行代码之外,您不会获得太多收益。

但是,如果您像这样声明循环:

for(int i = 0; i < x; i++)

您设法保持i在循环的范围内,而不是让它逃到其余的代码中。

此外,在 while 循环中,变量声明、条件和增量位于 3 个不同的位置。使用 for 循环,所有内容都集中在一个方便、易于阅读的地方。

最后的想法:
一个更重要的注意事项。两者之间存在语义差异。一般来说,While 循环意味着有无限次迭代。(即,直到文件被读取......不管它有多少行),并且 for 循环应该有更明确的迭代次数。(循环遍历集合中的所有元素,我们可以根据集合的大小来计算。)

于 2010-10-06T17:14:49.713 回答
86

for选择的原因之一while:可读性。

通过使用for循环,您明确表示您的意图是执行某种需要初始化、“步骤”操作和完成条件的操作。

while另一方面,您只是说您需要完成条件。

于 2010-10-06T17:14:14.770 回答
37

当我不一定需要计数器时,我使用“while”,例如当您从文件中读取并等待到达 EOF 时。在这种情况下,'for' 可能不是最好的选择。当您浏览数组中的项目时,我宁愿使用“for”,因为它可以更好地传达意图。

于 2010-10-06T17:14:09.083 回答
27

for() 和 while() 循环之间的一个显着区别是 while() 循环中的“继续”语句将分支到循环的顶部,而 for() 循环中的一个语句将分支到第三部分for() 子句的[条件后面的那个,通常用于碰撞变量]。

于 2010-10-06T17:49:16.407 回答
16

作为一名教师,我一直在以各种形式思考这个问题;我的建议总是归结为

  • for-loops 用于计数。往上数,往下数。
  • while/do-while构造适用于所有其他条件。 c!=EOF, diff<0.02, 等等。迭代器/枚举器是非常适合 for 循环的计数器。

即你int=0; while( ... )在我眼里是丑陋的。

于 2010-10-06T19:04:35.783 回答
15

为什么选择可乐而不是百事可乐?

在 WHILE 和 FOR 循环之间,您可以互换使用它们。要成为纯粹主义者,您可以根据条件的性质做出决定。如果您正在执行基于计数的循环,那么 FOR 循环将是最有意义的。

for( cur = 0; cur < myList.Length; cur++ ){
    doSomething( myList[cur] );
}

如果您正在执行基于逻辑的循环,那么 WHILE 将是最干净的实现

Iterator i = myObject.getIterator();
while( i.hasNext() ){
    doSomething( i.next() );
}
于 2010-10-06T18:01:29.690 回答
7

通常,我总是更喜欢 for 循环,即使对于循环与计数无关的情况,因为它将循环的维护本地化在一个位置。当其他人出现并决定添加/修改循环时,如果他们正在使用 FOR 循环,那么进行修改的人通常可以确信,只要他们不弄乱 FOR 表达式中的项目,他们不会破坏循环中的迭代。

然而,像 while 循环这样的东西需要程序员完全解析循环体,并了解它是如何迭代的,以确保在进行更改时保持循环维护代码未修改且顺序正确。

因此,我在实际上只需要 FOR 的中间部分的情况下使用 WHILE。

于 2010-10-07T02:30:43.757 回答
7

正如您所说,原因是语义和美学,而不是性能(它们编译的代码往往非常相似)。

也就是说,for通常在具有已知迭代次数的循环中,而while意味着条件不一定与您在循环中所做的事情相关,或者您一开始不知道会有多少次迭代是。

于 2010-10-06T17:16:36.943 回答
4

它们在功能上是相同的,但是可以说 for 循环不太容易出错,因为所有循环功能都在一起。如果你有几行分隔 i 的声明、while 声明和索引迭代器,你可能会忘记它,或者对它的使用方式感到困惑。当然,这都是主观的。

于 2010-10-06T17:15:37.193 回答
3

在像 Pascal 这样的语言中,for 和 while 结构有不同的应用。您将在 Pascal 中编写一个 for 循环,如下所示:

for i := 1 to 5 do
begin
{ some code here }
end

因此,您明确声明 i 递增 1。此处没有明确指定终止条件。因此,您只能在您知道循环将在实际循环执行开始之前运行特定预定次数的地方使用 for 循环。另一方面,您可以在 while 循环的情况下指定显式终止条件。

i:=0;
while (i<>5) do
begin
{ some code here }
i:=i+1;
end

因此,while 循环更加灵活。后来开发 C 时,虽然支持 for 和 while,但 for 构造的含义发生了变化,您可以使用布尔运算符添加显式终止条件。因此,在 C 和类 C 语言中,while 和 for 的功能是相同的,因此它更多地成为可读性问题而不是可用性问题。

于 2010-10-07T02:23:05.703 回答
3

这主要是可读性问题。通常,当您有定义的值范围进行迭代时,请使用 for 循环。当您不进行迭代或不知道退出条件何时为真时,请使用 while 循环。

从 java 的角度来看,我发现 for 循环对于集合非常方便:

for (Object o : objects){
    o.process();
}

比以下内容更容易阅读:

int i=0;
while(i < objects.size()){
    objects.get(i).process();
    i++;
}
于 2010-10-06T17:17:59.990 回答
3

它们通常会编译成相同的最终结果。大多数时候,我更喜欢 for's 或 for-each。写作

for (;x<5;x++){ 
    //do work 
} 

没那么险恶,但是写

while(x<5){
    x++
    //do work
}

代替

while(x<5){
    //do work
    x++
}

可能会使某些人感到困惑并导致错误。

于 2010-10-06T17:15:30.417 回答
3

在编程的早期,流行的数据结构是线性数组(又名向量),重复模式是遍历和使用数组的每个元素。这种情况很常见,以至于语言包含这种模式的特定语法:for循环。除了这种历史遗产之外,您还可以使用 while 循环(现在使用 F# 之类的函数式语言,您宁愿使用 List.map 或 List.fold ;-)

于 2010-10-06T17:16:52.957 回答
2

浏览其他(非常好的)答案,有一点我没有看到。(如果确实成功了,我会错过并道歉。)

我将给你两个看似语义相同的代码片段。

片段#1:

for (int a = 0; a < arr.length; a++) {
  /* do some work here */
}

片段#2:

int b = 0;
while (b < arr.length) {
  // do work
  b++;
}

他们看起来好像在做同样的事情,对吧?现在让我在每个片段中添加一行,让我们看看会发生什么:

片段#3:

for (int c = 0; c < arr.length; c++) {
  /* do some work here */
}
printf("%d\n", c);

片段#4:

int d = 0;
while (d < arr.length) {
  // do work
  d++;
}
printf("%d\n", d);

因此,当我编译一个嵌入了这四个片段的垃圾文件(加上一些胶水以使 arr.length 有意义)时,我收到以下错误:

$ clang junk.c
junk.c:20:17: error: use of undeclared identifier 'c'
        printf("%d\n", c);
                       ^
1 diagnostic generated.

事实证明,使用for循环允许您为虚拟计数器变量等提供更多局部性。这为您在重用变量名称时提供了更大的余地而不会发生冲突(尽管以增加潜在阴影为代价)。

于 2010-10-07T03:53:54.827 回答
1

简单的说:

'for' 循环倾向于用于迭代使用。您需要遍历数组,出于各种原因需要数字 1 到 100(或其他范围)。

“while”循环往往是条件循环。你想继续做某事,直到一个 contition 是错误的。假设您有一个名为“Toast”的类,并且您想将吐司煮至烤好,您将得到如下内容:

while (!toast.isToasted) cook(toast);

你总是可以(我想不出一个你不能的例子)写一个 for 循环作为一个 while 循环和一个 while 循环作为一个 for 循环,但是选择最先出现的情况通常归结为我的以上几点。

于 2010-10-07T12:30:18.427 回答
1

forwhile循环之间存在语义差异。使用for循环,迭代次数是预先定义的,而使用while循环则没有必要。

某些语言(例如 Ada)通过使for循环计数器成为循环体中的常量来强制执行此操作。因此,例如说:

for i in values'range loop
   ...
   i := i + 1;   -- this is illegal, as i is a constant within the loop body
end if;

for然而,这种语义差异对于大多数不将循环计数器视为常量的语言并不那么清楚。

于 2010-10-06T23:34:04.863 回答
1

可读性是非常重要的一点,但它是双向的。我会将 for 循环转换为 while 循环——即使我使用了一个计数器变量,否则使用 for 是“自然的”——这样更易读。当您在 for 的三个部分或多个计数器中的任何一个(与复杂有关)中有一个长或复杂的表达式时,这很常见。

Knuth 的半循环在几种语言中也能更好地工作,作为带中断的无限循环,而不是 for 循环。

但是,有一个非常重要的语义差异:

for (int i = 0; i < arr.length; i++) {
  if (filter(arr[i])) continue;
  use(arr[i]);
}

int i = 0;
while (i < arr.length) {
  if (filter(arr[i])) continue;
  use(arr[i]);
  i++;
}
于 2010-10-07T13:10:57.893 回答
1

可读性。而从老VB 6天下来,每当看到一会我就想哭。

在某些情况下,while 循环很好用。在对象上调用一个函数,该函数返回 true/false,但在该对象内迭代一个值。

示例是 C# 中的 DataReader:

List<string> strings = new List<string>();
while(DataReader.Read())
{
  strings.Add(DataReader["foo"].ToString());
}

for 循环允许您将工作封装在一个函数中,从而提供更好的内存管理。此外,如果您的 while 循环中有错误,它可能会演变成一个失控的循环,威胁到所有人的生命:

bool keepGoing = true;
while(keepgoing)
{
   try
   {
     //something here that causes exception, fails to set keepGoing = false;
     keepGoing = false;
   }
   catch(Exception)
   {
    //Do something, but forget to set keepGoing.
    //maybe there is always an exception...
   }

}

我也认为这只是一般做法。很像在建筑中。您使用钉子将屋顶平铺到螺柱上。你“可以”使用螺丝,他们会做同样的工作,但这不是常见的做法。

没有人说这是错的,我们只是说“请在同行的压力下放弃,以保持编码世界的运转”。

于 2010-10-06T18:42:34.747 回答
1

相关琐事:

在 Google 的新Go 语言中,他们决定不包含while语句。相反,它们允许您编写一个只有条件子句的for语句。所以相当于

while (a < b) { ... }

简直就是

for a < b { ... }
于 2010-10-07T09:33:23.997 回答
1

通常,while 循环和 for 循环之间的区别是语法而不是性能相关。也就是说,看起来这个问题已经为 Java 解决了:Java for loop vs. while loop。性能差异?

于 2010-10-06T17:17:50.973 回答
1

只需决定一个,然后在整个项目中复制并粘贴/调整它。更少的决定,更少的打字,更快的编码。可忽略的性能差异。

此外,我不与 Justin 保持i在循环范围内,并且我 var aL = array.length也在循环外使用。然后在循环构造函数中使用iand ,这样您就不会在每次命中时重新计算数组的长度(以及一遍又一遍地创建 var ;))。再次否定。性能真的很好(见我的回答的第一部分),除非你有非常大的阵列飞来飞去。如果您碰巧预先知道数组长度,请首先使用其固定长度启动它(在糟糕的浏览器上对内存分配有一点帮助;)如果这是客户端并且您有很多数据)。aLfor

例子

<script>
var i=0;
var myArray = ["D","R","Y"];//literal style will do for now;)
var aL=myArray.length; //or use 3 if known upfront
for(i;i<aL;i++){/*always do DRY things here*/}
</script>

还要确保满足条件时,问问自己“我还需要完成整个循环吗?” 如果不是,请不要忘记尽早跳出循环。

于 2010-10-06T21:05:18.787 回答
0

因为后者可以是一个班轮: while (++i < arr.length) { // 做工作 }

于 2010-10-07T04:27:04.870 回答
0

这只是我的逻辑,当我们知道迭代的确切计数时,我们通常使用 for 循环,而当我们通常想要检查条件时,我们使用 while 循环。然后我们根据您的要求使用它们。否则,它们都表现出相同的行为。

于 2010-10-07T12:16:02.577 回答
0

For 循环通常更容易并行化。由于程序可以提前知道将要执行的迭代次数以及迭代器在任何时候的值,因此使用 OpenMP 等 API 进行并行化是微不足道的。当然,如果您进入中断、继续和手动更改迭代器,这个优势就会消失。

于 2010-10-06T20:19:51.383 回答
0

在适当的时候使用 for 循环。while 解决方案有语法上的缺点(它更长),您必须在循环中的任何 continue 调用之前检查是否增加了 i 。

于 2010-10-06T17:14:17.063 回答
0

偏爱。对我来说,所有循环逻辑都内置在 for 语句中,因此您不必声明计数器变量或在实际循环中执行递增/递减操作。此外,您可以在 for 语句中声明计数器/索引。

于 2010-10-06T17:14:49.853 回答
0

一个原因是 while 的条件可以是一个字符串。

此外,如果我们将“Do”添加到组合中,当我们希望操作至少运行一次时,无论其当前状态如何,我们都可以使用 do while 循环。

于 2010-10-07T08:55:10.123 回答
0

一个while循环,定义为

while(condition)

表示这种编程模式:

1:
if(!condition) goto 2;
...
goto 1;
2:

而 for 循环,定义为

for(var i = seed; condition; operation)

代表这种模式:

var i = seed
1:
if(!condition) goto 2;
...
operation;
goto 1;
2:

这两种模式都非常常用,以至于它们已被命名并内置到语言中。

如果您需要定义一个计数器来控制您的循环,请使用 for 循环。如果没有,请使用 while 循环。

于 2010-10-08T06:52:56.857 回答