++i
ループ内とループi++
内の違いはありfor
ますか? それは単に構文の問題ですか?
23 に答える
a++は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++) { }
プリインクリメント ++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 など) の場合、パフォーマンスの違いはありません。ただし、ポスト インクリメント オペレータが絶対に必要なものでない限り、ガイドラインとしてプレ インクリメント オペレータに固執する価値があります。
ここでさらに議論があります。
C++ で STL を使用している場合は、イテレータで for ループを使用している可能性があります。これらには主にオーバーライドされた ++ 演算子があるため、事前インクリメントに固執することをお勧めします。ただし、コンパイラは常に賢くなり、新しいものは最適化を実行できるため、パフォーマンスの違いはありません。特に、インクリメントされる型がヘッダー ファイルでインラインで定義されている場合 (STL 実装ではよくあることです)、コンパイラがどのように動作するかを確認できます。メソッドが実装され、実行しても安全な最適化を知ることができます。それでも、ループは何度も実行されるため、事前インクリメントに固執する価値はあります。これは、小さなパフォーマンス ペナルティがすぐに増幅される可能性があることを意味します。
++ 演算子をオーバーロードできない C# などの他の言語では、パフォーマンスの違いはありません。ループ変数を進めるためにループで使用されます。プリインクリメント演算子とポストインクリメント演算子は同等です。
訂正: C# での ++ のオーバーロードは許可されています。ただし、C++ と比較して、C# では事前バージョンと事後バージョンを個別にオーバーロードできないようです。したがって、C# で ++ を呼び出した結果が変数に割り当てられていないか、複雑な式の一部として使用されていない場合、コンパイラは ++ の前後のバージョンを同等に機能するコードに削減すると想定します。
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 の値をインクリメントしてから読み取ります。
質問は:
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ループ本体内にあるコードの実行後にインクリメントされます。
あなたはループの違いについて尋ねるので、私はあなたが意味すると思います
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 の以前の値が割り当てられます。
このコードが示すように(コメントの分解されたMSILを参照)、C#3コンパイラーはforループでi++と++iを区別しません。i++または++iの値が使用されている場合、間違いなく違いがあります(これは、Visutal Studio 2008 /リリースビルドでコンパイルされました)。
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++;
}
}
}
}
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(...; ...; )) の場合、for ループに実際の違いはありませんが、他の場合に影響を与える可能性があります。
以下は Java サンプルとバイト コードです。post- と preIncrement はバイトコードに違いはありません。
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 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 ループの最後で実行されるため、結果を説明できることです。
はいあります。違いは戻り値にあります。「++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
++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;
}
@Jon Bが言うように、forループに違いはありません。
しかし、while
またはループでは、またはと比較している場合、いくつかdo...while
の違いを見つけることができます++i
i++
while(i++ < 10) { ... } //compare then increment
while(++i < 10) { ... } //increment then compare
次の i++ のため、javascript を使用する方がよい場合があります。
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から始めることができるからです。
ループには違いがある場合があります。これは、ポスト/プレインクリメントの実用的なアプリケーションです。
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-constructsはここでは除外されます)。
どちらも数値を増やします。++i
と同等i = i + 1
です。
i++
と++i
非常に似ていますが、まったく同じではありません。どちらも数値を増やしますが++i
、現在の式が評価される前に数値を増やしi++
ますが、式が評価された後に数値を増やします。
int i = 3;
int a = i++; // a = 3, i = 4
int b = ++a; // b = 4, a =
このリンクを確認してください。
のi
ユーザー定義型の場合、これらの演算子は、ループインデックスのコンテキストで意味のある異なるセマティックを持つ可能性があります(ただし、そうではありません)。これは、説明されているループの動作に影響を与える可能性があります(ただし、影響しないはずです)。
また、より簡単に最適化できるためc++
、一般的にプリインクリメント形式()を使用するのが最も安全です。++i
(スコット・ランガムは私をこの一口に殴りました。あなたを呪います、スコット)
他の言語についてはわかりませんが、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
私は++; ++私; どちらも式で使用されていないため、似ています。
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