for循环中的++i和i++有区别吗?这仅仅是语法问题吗?
一个(++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增加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等),没有性能差异。但是,作为指导原则,坚持使用前增量操作符是值得的,除非确实需要后增量操作符。
这里还有一些讨论。
In C++ if you're using STL, then you may be using for loops with iterators. These mainly have overridden ++ operators, so sticking to pre-increment is a good idea. Compilers get smarter all the time though, and newer ones may be able to perform optimizations that mean there's no performance difference - especially if the type being incremented is defined inline in header file (as STL implementations often are) so that the compiler can see how the method is implemented and can then know what optimizations are safe to perform. Even so, it's probably still worth sticking to pre-increment because loops get executed lots of times and this means a small performance penalty could soon get amplified.
在其他语言(如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循环中没有区别。
但在一段时间或做…While循环,如果你与++i或i++进行比较,你会发现一些不同
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
Foreach和while循环取决于您使用的增量类型。对于下面这样的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时,必须将I设置为-1以使循环与数组一起工作。
当使用i++时,下面的值将使用增加的值。你可以说i++是人类计数的方式,因为你可以从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<<" ";
}
输出: 0 0 1 2 - 2 3个3
增量后循环:
for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<" ";
cout<<k<<" ";
}
输出: 0 0 1 0 2 1 3 - 2
我希望通过比较输出可以清楚地看出差异。这里需要注意的是,递增/递减总是在for循环的末尾执行,因此结果可以解释。
我不知道其他语言,但在java++中,I是一个前缀增量,这意味着:将I增加1,然后在I所在的表达式中使用I的新值,i++是一个后缀增量,这意味着:在表达式中使用I的当前值,然后将其增加1。 例子:
public static void main(String [] args){
int a = 3;
int b = 5;
System.out.println(++a);
System.out.println(b++);
System.out.println(b);
} 输出为:
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++)
or
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循环中,++i和i++之间是有区别的,尽管在不寻常的用例中;当在for块中或在循环测试表达式中使用带有递增/递减操作符的循环变量,或与其中一个循环变量一起使用时。不,这不仅仅是语法问题。
因为i在代码中表示对表达式i求值,而运算符并不表示求值,而只是一个操作;
++i表示将i的值增加1,然后对i求值, i++表示对I求值,然后将I的值增加1。
因此,从每两个表达式中得到的内容是不同的,因为在每个表达式中求值的内容是不同的。i和i都一样
例如;
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)
}
要理解FOR循环的作用
上图显示FOR可以转换为WHILE,因为它们最终具有完全相同的汇编代码(至少在gcc中)。所以我们可以把FOR分解成几部分,来理解它的功能。
for (i = 0; i < 5; ++i) {
DoSomethingA();
DoSomethingB();
}
等于WHILE版本
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
}
It means that you can use FOR as a simple version of WHILE: The first argument of FOR (int i) is executed, outside, before the loop. The third argument of FOR (i++ or ++i) is executed, inside, in the last line of the loop. TL:DR: no matter whether i++ or ++i, we know that when they are standalone, they make no difference but +1 on themselves. In school, they usually teach the i++ way, but there are also lots of people prefer the ++i way due to several reasons. NOTE: In the past, i++ has very little impact on the performance, as it does not only plus one by itself, but also keeps the original value in the register. But for now, it makes no difference as the compiler makes the plus one part the same.
在某些情况下,++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的值,但由于一个简单的++/——操作符,我们改变了这个值。
所以在使用++/——操作符时要小心。
我希望我能使我的观点更容易理解。