当前位置:  开发笔记 > 编程语言 > 正文

循环中i ++和++ i之间的区别?

如何解决《循环中i++和++i之间的区别?》经验,为你挑选了10个好方法。

是否有差异++i,并i++在一个for循环?它只是一个语法的东西吗?



1> Chris S..:

a ++被称为后缀.

将1添加到a,返回旧值.

++ a被称为前缀.

将1添加到a,返回新值.

C#:

string[] items = {"a","b","c","d"};
int i = 0;
foreach (string item in items)
{
    Console.WriteLine(++i);
}
Console.WriteLine("");

i = 0;
foreach (string item in items)
{
    Console.WriteLine(i++);
}

输出:

1
2
3
4

0
1
2
3

foreachwhile循环取决于您使用的增量类型.对于像下面这样的for循环,没有区别,因为你没有使用i的返回值:

for (int i = 0; i < 5; i++) { Console.Write(i);}
Console.WriteLine("");
for (int i = 0; i < 5; ++i) { Console.Write(i); }

0 1 2 3 4
0 1 2 3 4

如果使用了已评估的值,则增量类型变得很重要:

int n = 0;
for (int i = 0; n < 5; n = i++) { }


我是唯一一个为什么这是接受的答案感到困惑的人?
没有乔恩.我对如此多的赞成票感到困惑.
@JonB我认为自你原来的评论以来答案已经有了很大的改进.也许编辑它以反映这一点.我只花了几分钟搞清楚这个答案出了什么问题,结果却发现它实际上比大多数人更好地回答了这个问题.
这甚至不是用户要求的。

2> Scott Langha..:

预增量++ i递增i的值并计算为新的递增值.

int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );

后增量i ++增加i的值并计算为原始的非增量值.

int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );

在C++中,通常首选预增量,您可以使用任何一种.

这是因为如果使用后增量,则可能需要编译器生成创建额外临时变量的代码.这是因为变量的先前值和新值都需要保持在某处,因为在被评估的表达式的其他地方可能需要它们.

因此,至少在C++中,可能存在性能差异,指导您选择使用哪种.

当递增的变量是具有重写的++运算符的用户定义类型时,这主要是一个问题.对于原始类型(int等),没有性能差异.但是,除非后增量运算符肯定是必需的,否则值得坚持使用预增量运算符作为指导.

这里还有一些讨论:https://web.archive.org/web/20170405054235/http :
//en.allexperts.com/q/C-1040/Increment-operators.htm

在C++中,如果您正在使用STL,那么您可能正在使用带迭代器的for循环.这些主要有重写的++运算符,所以坚持预增量是一个好主意.编译器总是变得更聪明,而较新的编译器可能能够执行优化,这意味着没有性能差异 - 特别是如果增加的类型是在头文件中内联定义的(因为STL实现经常是这样),以便编译器可以看到该方法已实现,然后可以知道哪些优化可以安全执行.即便如此,它仍然值得坚持预增量,因为循环执行很多次,这意味着很小的性能损失很快就会被放大.


在C#等其他语言中,++运算符不能重载,没有性能差异.在循环中用于推进循环变量,前后增量运算符是等效的.

更正:允许在C#中重载++.看来,与C++相比,在c#中你不能独立地重载前后版本.所以,我认为如果在C#中调用++的结果没有分配给变量或者作为复杂表达式的一部分使用,那么编译器会将++的前后版本缩减为等效执行的代码.


如果C++被命名为++ C,表明你可以使用它编写一个优化良好的代码,那不是很好吗?
现代编译器是否应该能够在结果值显然会被破坏的情况下优化它?
@che:这是一个很好的问题.C++编译器不能替换"CustomType ++;"的原因 用"++ CustomType;" 是因为无法保证两个用户定义的函数具有相同的效果.他们应该......但是不能保证.
@che - 当它是一个简单的类型时它们会这样做,但是重载operator ++(例如迭代器)的类是一个不同的故事.
@ michael.bartnett:好的一点是,在C#中重载++似乎确实可用.看起来,与c ++相比,在c#中你不能独立地重载前后版本.所以,我认为如果在C#中调用++的结果没有分配给变量或者作为复杂表达式的一部分使用,那么编译器会将++的前后版本缩减为等效执行的代码.

3> Jon B..:

在C#中,在for循环中使用时没有区别.

for (int i = 0; i < 10; i++) { Console.WriteLine(i); }

输出相同的东西

for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }

正如其他人所指出的那样,当用于一般的i ++和++时,我有一个微妙而重要的区别:

int i = 0;
Console.WriteLine(i++);   // Prints 0
int j = 0;
Console.WriteLine(++j);   // Prints 1

i ++读取i的值然后递增它.

++ i递增i的​​值然后读取它.


@MatthieuP - 我把这个问题读作"你是否在for循环中使用i ++或++ i这一点很重要".答案是"不,不是".
我不认为第一点是相关的.在for循环中(c#或不是),增量部分总是在循环体之后执行.执行后,无论是使用后增量还是预增量,都会修改变量.

4> Vinz..:

问题是:

for循环中++ i和i ++有区别吗?

答案是:.

为什么每个答案都必须详细解释有关前后递增的问题?

这个for循环:

for (int i = 0; // Initialization
     i < 5;     // Condition
     i++)       // Increment
{
   Output(i);
}

将不使用循环转换为此代码:

int i = 0; // Initialization

loopStart:
if (i < 5) // Condition
{
   Output(i);

   i++ or ++i; // Increment

   goto loopStart;
}

现在,如果你在这里放i++++i增加它是否重要?不,它不会因为增量操作的返回值无关紧要.i将在for循环体内的代码执行后递增.



5> Johannes Sch..:

既然你在循环中询问差异,我想你的意思是

for(int i=0; i<10; i++) 
    ...;

在这种情况下,您在大多数语言中没有区别:无论您是否写入i++,循环的行为都相同++i.在C++中,您可以编写自己的++运算符版本,并且可以为它们定义单独的含义,如果它i是用户定义的类型(例如,您自己的类).

之所以无关紧要,是因为你没有使用的值i++.另一件事是当你这样做的时候

for(int i=0, a = 0; i<10; a = i++) 
    ...;

现在,有有差别,因为其他人指出,i++是指增量,但评估的前值,但++i意味着增量,但计算结果为i(因此它会评估为新值).在上述情况下,a分配i的先前值,而i增加.


在C++中,编译器并不总是可以避免使用临时的,因此首选的是预增量形式.

6> Joe Erickson..:

正如此代码所示(请参阅注释中的差异化MSIL),C#3编译器在for循环中对i ++和++ i没有区别.如果正在使用i ++或++ i的值,那肯定会有区别(这是在Visutal Studio 2008/Release Build中编译的):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PreOrPostIncrement
{
    class Program
    {
        static int SomethingToIncrement;

        static void Main(string[] args)
        {
            PreIncrement(1000);
            PostIncrement(1000);
            Console.WriteLine("SomethingToIncrement={0}", SomethingToIncrement);
        }

        static void PreIncrement(int count)
        {
            /*
            .method private hidebysig static void  PreIncrement(int32 count) cil managed
            {
              // Code size       25 (0x19)
              .maxstack  2
              .locals init ([0] int32 i)
              IL_0000:  ldc.i4.0
              IL_0001:  stloc.0
              IL_0002:  br.s       IL_0014
              IL_0004:  ldsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
              IL_0009:  ldc.i4.1
              IL_000a:  add
              IL_000b:  stsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
              IL_0010:  ldloc.0
              IL_0011:  ldc.i4.1
              IL_0012:  add
              IL_0013:  stloc.0
              IL_0014:  ldloc.0
              IL_0015:  ldarg.0
              IL_0016:  blt.s      IL_0004
              IL_0018:  ret
            } // end of method Program::PreIncrement             
             */
            for (int i = 0; i < count; ++i)
            {
                ++SomethingToIncrement;
            }
        }

        static void PostIncrement(int count)
        {
            /*
                .method private hidebysig static void  PostIncrement(int32 count) cil managed
                {
                  // Code size       25 (0x19)
                  .maxstack  2
                  .locals init ([0] int32 i)
                  IL_0000:  ldc.i4.0
                  IL_0001:  stloc.0
                  IL_0002:  br.s       IL_0014
                  IL_0004:  ldsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
                  IL_0009:  ldc.i4.1
                  IL_000a:  add
                  IL_000b:  stsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
                  IL_0010:  ldloc.0
                  IL_0011:  ldc.i4.1
                  IL_0012:  add
                  IL_0013:  stloc.0
                  IL_0014:  ldloc.0
                  IL_0015:  ldarg.0
                  IL_0016:  blt.s      IL_0004
                  IL_0018:  ret
                } // end of method Program::PostIncrement
             */
            for (int i = 0; i < count; i++)
            {
                SomethingToIncrement++;
            }
        }
    }
}



7> Cody Brociou..:

一个(++ i)是preincrement,一个(i ++)是postincrement.不同之处在于从表达式立即返回的值.

// Psuedocode
int i = 0;
print i++; // Prints 0
print i; // Prints 1
int j = 0;
print ++j; // Prints 1
print j; // Prints 1

编辑:Woops,完全忽略了循环方面的事情.当for循环是'step'部分(for(...; ...;))时,for循环没有实际的区别,但它可以在其他情况下发挥作用.



8> 小智..:

这是一个Java-Sample和Byte-Code,post-和preIncrement在Bytecode中没有区别:

public class PreOrPostIncrement {

    static int somethingToIncrement = 0;

    public static void main(String[] args) {
        final int rounds = 1000;
        postIncrement(rounds);
        preIncrement(rounds);
    }

    private static void postIncrement(final int rounds) {
        for (int i = 0; i < rounds; i++) {
            somethingToIncrement++;
        }
    }

    private static void preIncrement(final int rounds) {
        for (int i = 0; i < rounds; ++i) {
            ++somethingToIncrement;
        }
    }
}

现在为字节码(javap -private -c PreOrPostIncrement):

public class PreOrPostIncrement extends java.lang.Object{
static int somethingToIncrement;

static {};
Code:
0:  iconst_0
1:  putstatic   #10; //Field somethingToIncrement:I
4:  return

public PreOrPostIncrement();
Code:
0:  aload_0
1:  invokespecial   #15; //Method java/lang/Object."":()V
4:  return

public static void main(java.lang.String[]);
Code:
0:  sipush  1000
3:  istore_1
4:  sipush  1000
7:  invokestatic    #21; //Method postIncrement:(I)V
10: sipush  1000
13: invokestatic    #25; //Method preIncrement:(I)V
16: return

private static void postIncrement(int);
Code:
0:  iconst_0
1:  istore_1
2:  goto    16
5:  getstatic   #10; //Field somethingToIncrement:I
8:  iconst_1
9:  iadd
10: putstatic   #10; //Field somethingToIncrement:I
13: iinc    1, 1
16: iload_1
17: iload_0
18: if_icmplt   5
21: return

private static void preIncrement(int);
Code:
0:  iconst_0
1:  istore_1
2:  goto    16
5:  getstatic   #10; //Field somethingToIncrement:I
8:  iconst_1
9:  iadd
10: putstatic   #10; //Field somethingToIncrement:I
13: iinc    1, 1
16: iload_1
17: iload_0
18: if_icmplt   5
21: return

}



9> user3304868..:

如果在循环中增加后没有使用该值,则没有区别.

for (int i = 0; i < 4; ++i){
cout<

两个循环都将打印0123.

但是当您在循环中使用增量/减量后的值时,差异就会出现,如下所示:

预增量循环:

for (int i = 0,k=0; i < 4; k=++i){
cout<

输出:0 0 1 1 2 2 3 3

后增量循环:

for (int i = 0, k=0; i < 4; k=i++){
cout<

输出:0 0 1 0 2 1 3 2

我希望通过比较输出来区分.这里要注意的是增量/减量总是在for循环结束时执行,因此可以解释结果.



10> David Morton..:

就在这里.差异在于返回值."++ i"的返回值将是递增i 的值."i ++"的返回将是递增的值.这意味着代码如下所示:

int a = 0;
int b = ++a; // a is incremented and the result after incrementing is saved to b.
int c = a++; // a is incremented again and the result before incremening is saved to c.

因此,a将为2,并且b和c将各自为1.

我可以像这样重写代码:

int a = 0; 

// ++a;
a = a + 1; // incrementing first.
b = a; // setting second. 

// a++;
c = a; // setting first. 
a = a + 1; // incrementing second. 

推荐阅读
农大军乐团_697
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有