循环中增量前和增量后的区别?

for循环中,++ii++有区别吗?这仅仅是语法问题吗?

308009 次浏览

一个(++i)是前增量,一个(i++)是后增量。区别在于表达式立即返回什么值。

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

编辑:哎呀,完全忽略了循环方面的事情。在for循环中,当它是'step'部分(for(…;…。)),但它也可以在其他情况下发挥作用。

在c#中没有区别在for循环中使用时

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

输出和

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

正如其他人指出的那样,在一般情况下i++和++i有一个微妙但显著的区别:

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

i++读取I的值,然后增加它。

++i增加i的值,然后读取它。

是的,有。区别在于返回值。"++i"的返回值将是加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.

在这两种情况下,'i'将加1。

但是当你在表达式中使用它时,就有区别了,例如:

int i = 1;
int a = ++i;
// i is incremented by one and then assigned to a.
// Both i and a are now 2.
int b = i++;
// i is assigned to b and then incremented by one.
// b is now 2, and i is now 3

Pre-increment + +我增加i的值并计算为新的增量值。

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

Post-increment我+ +将i的值加1,并计算为原始的不加1的值。

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

在c++中,如果可以使用前递增,则通常是首选。

这是因为如果使用后增量,它可能要求编译器必须生成创建额外临时变量的代码。这是因为被递增的变量的前值和新值都需要保存在某个地方,因为它们可能在被求值的表达式的其他地方被需要。

因此,至少在c++中,可以有性能差异来指导您选择使用哪一种。

这主要只在被递增的变量是用户定义的具有重写++操作符的类型时才会出现问题。对于基本类型(int等),没有性能差异。但是,作为指导原则,坚持使用前增量操作符是值得的,除非确实需要后增量操作符。

还有一些讨论在这里

在c++中,如果你使用的是STL,那么你可以使用带有迭代器的for循环。这些操作符主要覆盖了++操作符,因此坚持预递增是一个好主意。编译器一直在变得更智能,新的编译器可能能够执行优化,这意味着没有性能差异——特别是当被递增的类型在头文件中内联定义时(STL实现通常是这样),这样编译器可以看到方法是如何实现的,然后可以知道执行哪些优化是安全的。即便如此,可能仍然值得坚持预增量,因为循环执行了很多次,这意味着一个小的性能损失可能很快就会被放大。


在其他语言(如c#)中,c++操作符不能重载,在性能上没有区别。在循环中用于使循环变量前进,前增量操作符和后增量操作符是等效的。

更正:在c#中重载c++是允许的。不过,与c++相比,在c#中,你不能独立地重载前版本和后版本。因此,我假设在c#中调用++的结果没有被赋值给变量或用作复杂表达式的一部分,那么编译器会将++的前后版本简化为执行等效的代码。

既然你问了循环中的区别,我猜你的意思是

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是递增的。

正如@Jon B所说,在for循环中没有区别。

但是在whiledo...while循环中,如果你与++ii++进行比较,你会发现一些不同之处

while(i++ < 10) { ... } //compare then increment


while(++i < 10) { ... } //increment then compare

对于用户定义类型的i,这些操作符可以(但是不应该)在循环索引上下文中具有有意义的不同语义,这可能(但不应该)影响所描述的循环的行为。

同样,在c++中,通常使用预增量形式(++i)是最安全的,因为它更容易优化。Scott Langham 先告诉我这个趣闻;诅咒你,斯科特)

a++被称为后缀。

a加1,返回原来的值。

++a被称为前缀。

对a加1,返回新值。

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++) { }

正如这段代码所示(请参阅注释中拆解的MSIL), c# 3编译器在for循环中不区分i++和++i。如果取i++或++i的值,肯定会有区别(这是在visual 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++;
}
}
}
}

对于循环可能会有不同。这是后增量/前增量的实际应用。

        int i = 0;
while(i++ <= 10) {
Console.Write(i);
}
Console.Write(System.Environment.NewLine);


i = 0;
while(++i <= 10) {
Console.Write(i);
}
Console.ReadLine();

虽然第一个数到11,循环11次,但第二个不是。

这通常用于简单的while(x——> 0);- -循环迭代数组中的所有元素(这里不包括foreach-construct)。

关于++i和i++,不仅仅是循环和性能差异。++i返回一个l值,i++返回一个r值。基于此,可以对(++i)执行许多操作,但不能对(i++)执行许多操作。

1- It is illegal to take the address of post increment result. Compiler won't even allow you.
2- Only constant references to post increment can exist, i.e., of the form const T&.
3- You cannot apply another post increment or decrement to the result of i++, i.e., there is no such thing as I++++. This would be parsed as ( i ++ ) ++ which is illegal.
4- When overloading pre-/post-increment and decrement operators, programmers are encouraged to define post- increment/decrement operators like:


T& operator ++ ( )
{
// logical increment
return *this;
}


const T operator ++ ( int )
{
T temp( *this );
++*this;
return temp;
}

在javascript中由于以下原因i++可能更好使用:

var i=1;
alert(i++); // before, 1. current, 1. after, 2.
alert(i); // before, 2. current, 2. after, 2.
alert(++i); // before, 2. current, 3 after, 3.

虽然数组(我认为是所有)和其他一些函数和调用使用0作为起点,但在使用+ +我时,必须将I设置为-1以使循环与数组一起工作。

当使用我+ +时,下面的值将使用增加的值。你可以说我+ +是人类计数的方式,因为你可以从0开始。

下面是一个Java-Sample和字节码,后增量和前增量显示字节码没有区别:

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."<init>":()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


}

如果在循环中不使用增量之后的值,则没有区别。

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

这两个循环都输出0123。

但是当你在循环中使用自增/自减后的值时,区别就来了:

预增量循环:

for (int i = 0,k=0; i < 4; k=++i){
cout<<i<<" ";
cout<<k<<" ";
}
< p >输出: 0 0 1 2 - 2 3 3 < / p >

增量后循环:

for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<" ";
cout<<k<<" ";
}
< p >输出: 0 0 1 0 2 1 3 2 < / p >

我希望通过比较输出可以清楚地看出差异。这里需要注意的是,递增/递减总是在for循环的末尾执行,因此结果可以解释。

我不知道其他语言,但在Java中+ +我是一个前缀增量,这意味着:将增加1,然后在所在的表达式中使用I的新值,而我+ +是一个后缀增加,这意味着以下:在表达式中使用的当前值,然后将其增加1。 例子:< / p >

public static void main(String [] args){


int a = 3;
int b = 5;
System.out.println(++a);
System.out.println(b++);
System.out.println(b);
< p >} 输出是:

  • 4
  • 5
  • 6

问题是:

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

答案是:没有

为什么每个答案都必须详细解释前增量和后增量,而这个问题甚至都没有问过?

这样的循环:

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循环体内的代码执行之后递增。

我很奇怪为什么这么多人把for循环中的增量表达式写成i++。

在for循环中,当第三个组件是一个简单的增量语句时,例如

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

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

结果执行没有区别。

我+ +;+ +我;两者都是相似的,因为它们不在表达式中使用。

class A {


public static void main (String []args) {


int j = 0 ;
int k = 0 ;
++j;
k++;
System.out.println(k+" "+j);


}}


prints out :  1 1

是的,在for循环中,++ii++之间是有区别的,尽管在不寻常的用例中;当使用在for语句块中在循环测试表达式中其中一个循环变量带有自增/自减操作符的循环变量时。不,这不仅仅是语法问题。

因为i在代码中表示对表达式i求值,而运算符并不表示求值,而只是一个操作;

  • ++i表示将i的值增加1,然后计算i
  • i++表示对i求值,然后将i的值加1。

因此,从每两个表达式中得到的内容是不同的,因为在每个表达式中求值的内容是不同的。--ii--都是一样的

例如;

let i = 0


i++ // evaluates to value of i, means evaluates to 0, later increments i by 1, i is now 1
0
i
1
++i // increments i by 1, i is now 2, later evaluates to value of i, means evaluates to 2
2
i
2

在不寻常的用例中,下一个例子听起来有用与否并不重要,它显示了差异

for(i=0, j=i; i<10; j=++i){
console.log(j, i)
}


for(i=0, j=i; i<10; j=i++){
console.log(j, i)
}

来理解循环的作用

enter image description here

上图显示,可以转换为,因为它们最终具有完全相同的汇编代码(至少在gcc中)。因此,我们可以将分解成几部分,以了解它的功能。

for (i = 0; i < 5; ++i) {
DoSomethingA();
DoSomethingB();
}

等于版本

i = 0; //first argument (a statement) of for
while (i < 5 /*second argument (a condition) of for*/) {
DoSomethingA();
DoSomethingB();
++i; //third argument (another statement) of for
}

这意味着你可以使用作为的简单版本:

  1. (int i)的第一个参数在循环之前的外部执行。

  2. (i++ or ++i)的第三个参数在循环的最后一行中执行。

TL:DR:无论是i++还是++i,我们知道当它们是独立的时,它们没有区别,只是对自己+1。

在学校里,他们通常教i++的方式,但也有很多人更喜欢++i的方式,因为几个原因

注意:在过去,i++对性能的影响很小,因为它不仅自己加1,而且还在寄存器中保持原始值。但是现在,它没有区别,因为编译器使加1部分相同。

在某些情况下,++i和i+1可能会给出不同的结果,-i, i - 1等也是如此。

这并不是因为递增和递减操作符的工作方式有缺陷,而是因为新程序员有时会忽略一个小事实。

根据经验,不要在数组的方括号内使用inc/dec。例如,我不会用arr[++ I]来代替arr[I + 1]。虽然两者得到的i值是一样的,但这里我们忽略了一些东西。

如果循环条件基于i的执行值,那么将arr[i + 1]替换为arr[++i]将导致错误。为什么?

假设i = 5,那么arr[i + 1]意味着arr[6],而arr[++i]虽然意味着arr[6],但也会将i的值改变为6,这可能不是我们想要做的事情。我们可能不想改变i的值,但由于一个简单的++/——操作符,我们改变了这个值。

所以在使用++/——操作符时要小心。

我希望我能使我的观点更容易理解。