web-dev-qa-db-ja.com

ループ内のi ++と++ iの違いは?

forループ内の++ii++に違いはありますか?それは単なるシンタックスなのでしょうか。

278
GurdeepS

++はpostfixとして知られています。

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

++ 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#で++を呼び出した結果が変数に割り当てられていない場合、または複雑な式の一部として使用されていない場合、コンパイラは前後のバージョンの++を同等に機能するコードに減らします。

207
Scott Langham

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の値をインクリメントしてから読み込みます。

77
Jon B

質問は:

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ループ本体内にあるコードの実行後に増分されます。

36
Vinz

あなたはループの違いについて尋ねるので、私はあなたが意味すると思います

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

その場合、ほとんどの言語で違いはありません。ループは、i++++iのどちらを書いても同じように動作します。 C++では、独自のバージョンの++演算子を書くことができます。また、iがユーザー定義型(たとえば、独自のクラス)の場合は、それらに別々の意味を定義することができます。

上記のことが問題にならないのは、i++の値を使わないからです。別のことはあなたがするときです

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

さて、is違いがあります。他の人が指摘するように、i++インクリメント、しかし前の値に評価する、しかし++iインクリメント、しかし評価するにはi(したがって、新しい値に評価されます)。上記の場合、aには前のiの値が割り当てられ、iはインクリメントされます。

このコードが示すように(コメント内の分解された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++;
            }
        }
    }
}
15
Joe Erickson

1つ(++ i)は前インクリメント、1つ(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(...; ...;))の場合、forループに実際の違いはありませんが、他の場合には効果があります。

14
Cody Brocious

これがJavaサンプルであり、Byte-Code、post-and 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."<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

}
8

ループ内でインクリメント後の値を使用していないのであれば、違いはありません。

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 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ループの最後で行われるため、結果を説明できることです。

6
user3304868

はいあります。違いは戻り値にあります。 "++ i"の戻り値は、after 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. 
5
David Morton

どちらの場合も実際の違いはありません。 '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
4
CMS

++ 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;
}
3
Tanveer Badar

それが私の頭を悩ませます。なぜなら、人々はforループでi ++としてインクリメント式を書くかもしれません。

Forループで、3番目の要素が次のように単純なincrementステートメントの場合

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

または

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

実行結果に違いはありません。

3
Mont Pierce

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 ++が人間の数え方であると言えるでしょう、なぜならあなたはで始めることができるからです。

3
xaddict

@ Jon B の通り、forループに違いはありません。

しかしwhileまたはdo...whileループでは、++iまたはi++と比較している場合は、いくつかの違いがあります。

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

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

ループには違いがあります。これはpost/pre-incrementの実用的なアプリケーションです。

        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回ループしますが、2番目はしません。

ほとんどの場合、これは単純なwhile(x--> 0)で使用されます。 - - たとえば、配列のすべての要素を繰り返すためのループ(ここではforeach-constructを除く)。

1
Leonidas

両方とも数を増やします。 ++ii = i + 1と同等です。

i++++iはよく似ていますが、まったく同じではありません。両方とも数値をインクリメントしますが、++iは現在の式が評価される前に数値をインクリメントしますが、i++は式が評価された後に数値をインクリメントします。

int i = 3;
int a = i++; // a = 3, i = 4
int b = ++a; // b = 4, a = 

--- このリンク を確認してください。

1
Boubakr

はい、forループでは++ii++の間に違いがあります。インクリメント/デクリメント演算子を使用したループ変数が使用されている場合forブロック内またはループテスト式内またはループ変数の1つを使用 。いいえ、それは単なる構文上の問題ではありません。

コード内のiは式iを評価することを意味し、演算子は評価を意味するのではなく単なる操作を意味します。

  • ++iiの値を1増やし、後でiを評価することを意味します。
  • i++は、iを評価し、後でiの値を1増やします。

したがって、評価されるものがそれぞれ異なるため、2つの式それぞれから得られるものは異なります。 --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)
}
1
Selçuk