何时执行增量表达式

时间:2013-12-11 16:15:40

标签: c# for-loop increment

请告诉我为什么这个C#for循环执行后的和的值是20而不是30:

for (int i = 2; i < 10; i += 2)
{
    sum += i;
}

在我看来,在第一次迭代结束时,我将是2和总和2,在第二次结束时我将是4并且总和6,然后是6和12,然后是8和20.然后,当循环开始进入第5次迭代时,我仍然会在8时小于10,所以我会增加到10并且sum将是20 + 10 = 30.然后下一次i = 10,所以执行停止。但答案是20.为什么循环不进入第5次迭代?请对我温柔。

非常感谢您的启发。

5 个答案:

答案 0 :(得分:11)

4 timesi2, 4, 6,时,循环执行8 总计是20。

这里没有什么可以解决的谜。当i达到10时,for条件i < 10的评估为false,因此,10永远不会添加到sum变量

要完成答案,for statement的逻辑很简单:

  • 设置控制退出表达式(i=2)
  • 的变量的初始值
  • 评估退出表达式,如果为true,则输入for body,如果为false,则退出(i < 10)
  • 执行for body { ... whatever... }
  • 增加所需步骤的变量(i+=2)
  • 从评估退出表达式重新开始

答案 1 :(得分:2)

Loop 0 : i = 2, sum = 0 + 2 = 2
Loop 1 : i = 2 + 2 = 4, sum = 2 + 4 = 6
Loop 2 : i = 4 + 2 = 6, sum = 6 + 6 = 12
Loop 3 : i = 6 + 2 = 8, sum = 12 + 8 = 20
Loop 4 : i = 8 + 2 = 10, for loop stops.

Result: sum = 20

你写的for循环与:

相同
int i = 2;
while(true)
{
  if (i < 10)
  {
      sum += i;
  }
  else break;

  i += 2;
}

所以i递增然后进行评估,如果它不符合条件,则循环将被破坏。

答案 2 :(得分:1)

for (a;b;c) d;中,评估顺序是a,b,d,(c,b,d)其中(c,b,d)重复(如果bfalse,循环在那里破裂)。你似乎认为顺序是(b,c,d)。单步执行调试器中的代码将使此清楚。

在您的情况下,这意味着在i == 8之后,i会增加到10,然后会对i < 10进行测试;由于它是false,因此在将10添加到sum之前,循环会中断。对于for循环来说,这是一种更简单自然的方式,尤其是在循环数组的情况下:

// actual; i will have values from 0 (inclusive) to array.Length (exclusive)
for (int i = 0; i < array.Length; i++)
// if it worked how you assumed, it'd be
for (int i = 0; i < array.Length - 1; i++)
// but the last time you go through the loop, i < array.Length - 1 isn't true

答案 3 :(得分:0)

您似乎对for的运作方式存在误解。我将循环转换为执行的语句,因此您可以获得更好的想法:

int i = 2;
if (i < 10) {
    sum += i; // sum = 2
}
i += 2; // i = 4
if (i < 10) {
    sum += i; // sum = 6
}
i += 2; // i = 6
if (i < 10) {
    sum += i; // sum = 12
}
i += 2; // i = 8
if (i < 10) {
    sum += i; // sum = 20
}
i += 2; // i = 10
if (i < 10) {
    // nothing, since 10 <= 10, but *not* 10 < 10
}

答案 4 :(得分:0)

正如其他人已经指出的那样,答案是循环没有进入第5次迭代,因为你的例子中的[stop-]条件是'&lt;' (小于运算符)并且不是'&lt; ='(小于或等于)以便循环的数量,其可以被定义为'2n&lt; 10'解析为'n&lt; 5',其中4是n的最接近的有效匹配。

您可能会发现the MS docs about it有帮助。这是一段摘录:

  

for(initializer; condition; iterator)

  body
     

初始化部分设置初始条件。在进入循环之前,本节中的语句只运行一次。该部分只能包含以下两个选项之一。

     
      
  • 本地循环变量的声明和初始化,如第一个示例所示(int i = 1)。该变量是循环的局部变量,无法从循环外部访问。

  •   
  • 零个或多个语句表达[...]

  •   
     

条件部分包含一个布尔表达式,该表达式经过评估以确定循环是应该退出还是应该再次运行。

     

迭代器部分定义了循环体的每次迭代后发生的事情。迭代器部分包含零个或多个[...]语句表达式,以逗号[...]

分隔

作为旁注,可能值得一提的是关系测试的运算符,如'&lt;'并且'&lt; ='可能会因用户定义的类型而重载并使循环难以读取,但由于您使用int作为控件变量类型(不是用户定义的类型),因此您的情况并非如此示例

C# language specification - ECMA-334在“12.3.3.9 For语句”中显示了一个非常明确的定义,它也解释了for循环

for (int i = 2; i < 10; i += 2)
{
  sum += i;
}

可以转换为while循环

int sum = 0;
int i = 2;
while (i < 10)
{
    sum += i;
    i += 2;
}

使指令的顺序更加明显。

使用ildasm,除了一些NOP指令外,两个循环的输出是相同的。这是一个带注释的小版本:

.method private hidebysig static void  Testloop() cil managed
{
  // Code size       27 (0x1b)
  .maxstack  2
  .locals init ([0] int32 sum,      <-- this is location 0 --> 1. int sum = 0;
                [1] int32 i,        <-- this is location 1 --> 2. int i = 2;
                [2] bool CS$4$0000) <-- this is location 2 --> 3. unnamed temporary result storage for the i < 10 comparison
  IL_0000:  nop --> no operation is the machine code equivalent of a space character and can be ignored
  IL_0001:  ldc.i4.0          --> 1. int sum = 0;
  IL_0002:  stloc.0           --> 1.
  IL_0003:  ldc.i4.2          --> 2. int i = 2;
  IL_0004:  stloc.1           --> 2.
  IL_0005:  br.s  IL_0011     --> branch to target IL_0011, which is a "goto" and jumps over the conditional check and iterator code which starts at IL_0007
  IL_0007:  nop --> no operation is the machine code equivalent of a space character and can be ignored
  IL_0008:  ldloc.0           --> 5. sum += i
  IL_0009:  ldloc.1           --> 5.
  IL_000a:  add               --> 5.
  IL_000b:  stloc.0           --> 5.
  IL_000c:  nop --> no operation is the machine code equivalent of a space character and can be ignored
  IL_000d:  ldloc.1           --> 6. i += 2
  IL_000e:  ldc.i4.2          --> 6.
  IL_000f:  add               --> 6.
  IL_0010:  stloc.1           --> 6.
  IL_0011:  ldloc.1           --> 3. i < 10
  IL_0012:  ldc.i4.s   10     --> 3.
  IL_0014:  clt               --> 3.
  IL_0016:  stloc.2           --> 4. continue until ( 3. ) is true (meaning, i >= 10) by jumping back to the start at IL_0007
  IL_0017:  ldloc.2           --> 4. 
  IL_0018:  brtrue.s  IL_0007 --> 4.
  IL_001a:  ret --> the closing bracket of the method Testloop()
} // end of method Program::Testloop