web-dev-qa-db-ja.com

forループの反復部分でpreからpostの増分を変更しても、違いが生じないのはなぜですか?

なぜこれなのか

 int x = 2;
    for (int y =2; y>0;y--){
        System.out.println(x + " "+ y + " ");
        x++;
    }

これと同じように印刷しますか?

 int x = 2;
        for (int y =2; y>0;--y){
            System.out.println(x + " "+ y + " ");
            x++;
        }

私が理解している限り、ポストインクリメントは最初に「そのまま」使用され、次にインクリメントされます。プレインクリメントは最初に追加されてから使用されます。これがforループの本体に適用されないのはなぜですか?

39
andandandand

ループは次と同等です。

int x = 2;
{
   int y = 2;
   while (y > 0)
   {
      System.out.println(x + " "+ y + " ");
      x++;
      y--; // or --y;
   }
}

そのコードを読むことからわかるように、forループの3番目のセクションでpostまたはpredecrement演算子を使用するかどうかは関係ありません。

より一般的には、次の形式のforループ:

for (ForInit ; Expression ; ForUpdate)
    forLoopBody();

whileループとまったく同じです。

{
    ForInit;
    while (Expression) {
        forLoopBody();
        ForUpdate;
    }
}

Forループはよりコンパクトであるため、このような一般的なイディオムの解析が容易になります。

58
Paul Wagland

これらを視覚化するには、forループをwhileループに展開します。

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

展開先:

int i = 0;
while (i < 5) {
    do_stuff(i);
    ++i;
}

インクリメント式の結果(インクリメントの前または後の値)は同じステートメント内で使用されないため、ループカウンターでポストインクリメントを行うかプレインクリメントを行うかは重要ではありません。

28
tdammers

それがあなたの懸念であるならば、パフォーマンスの点で違いはありません。 use it duringインクリメントする場合にのみ、誤って使用できます(したがってエラーの影響を受けやすくなります)。

考えてみましょう:

_for (int i = 0; i < 3;)
   System.out.print(++i + ".."); //prints 1..2..3


for (int i = 0; i < 3;)
   System.out.print(i++ + ".."); //prints 0..1..2
_

または

_for (int i = 0; i++ < 3;)
   System.out.print(i + ".."); //prints 1..2..3


for (int i = 0; ++i < 3;)
   System.out.print(i + ".."); //prints 1..2
_

ただし、興味深い詳細は、通常のイディオムではforステートメントのインクリメント式で_i++_を使用することであり、Javaコンパイラーは_++i_が使用されます。

17
BalusC

++ iとi ++は、int num = i ++やintnum = ++ iなどの代入演算子やその他の式と組み合わせて使用​​すると違いが生じます。上記のFORループでは、他の式と組み合わせて使用​​されないため、インクリメント条件のみがあり、違いはありません。この場合、それはi = i +1のみを意味します。

13
Sachin Shanbhag

このループは、このwhileループと同じです。

int i = 0;
while(i < 5)
{
     // LOOP
     i++; // Or ++i
}

そうです、それは同じでなければなりません。

6
Cedric H.

その声明はそれ自体のものだからです。増分の順序はそこでは重要ではありません。

5
Noon Silk

インクリメントステートメントが実行された後にiの値が比較されるため、これら2つのケースは同等です。しかし、あなたがした場合

if (i++ < 3) 

versus

if (++i < 3)

あなたは物事の順序について心配しなければならないでしょう。

そして、あなたがした場合

i = ++i + i++;

その後、あなたはただのナッツです。

4
Paul Tomblin

あなたの例には何もないのでsing pre-またはpost-incrementsから返される値。 System.out.println()++xx++でラップして、違いを確認してください。

3
Alan Krueger

forループに関するJava言語仕様の章 から:

BasicForStatement:

    for ( ForInit ; Expression ; ForUpdate ) Statement

... ForUpdate部分が存在する場合、式は左から右に順番に評価されます。 それらの値がある場合は破棄されます。... ForUpdate部分が存在しない場合、アクションは実行されません。

(ハイライトは私のものです)。

3
ChssPly76

「for(初期;比較;インクリメント)」の「インクリメント」項目はステートメントの結果を使用せず、サイド)に依存しているため、出力は同じです。 -effectステートメントの。この場合は「i」をインクリメントします。これは両方の場合で同じです。

3
user207421

この例を試してください:

int i = 6;
System.out.println(i++);
System.out.println(i);

i = 10;
System.out.println(++i);
System.out.println(i);

あなたはそれがこれから何をするかを理解することができるはずです。

2
Noel M

チェックは、インクリメント引数が評価される前に実行されます。 'increment'操作は、最初に宣言されていても、ループの最後で実行されます。

2
Kylar

yの値はforステートメントで計算され、xの値は独自の行で計算されるため、System.out.printlnでは参照されるだけです。

System.out.println内でデクリメントすると、異なる結果が得られます。

System.out.println(y--);
System.out.println(--y);
1

forループが式i++または++iの結果を何かに使用した場合、それは真になりますが、そうではありません。副作用があるという理由だけで存在します。

そのため、数式だけでなく、voidメソッドを配置することもできます。

1
fortran

ここには良い答えがたくさんありますが、これが役立つ場合:

Y--および--yは、副作用のある式、またはステートメントの後に式が続くものと考えてください。 y--は次のようなものです(これらの例を疑似アセンブリと考えてください):

decrement y
return y

そして--yはこれを行います:

store y into t
decrement y
load t
return t

ループの例では、どちらの方法でも戻り値を破棄し、副作用のみに依存しています(ループチェックは、デクリメントステートメントの実行後に発生します。デクリメントによって返された値を受信/チェックしません)。

1
danben

For "arguments"のすべての部分が別々のステートメントであるため、違いはありません。

そして興味深いのは、コンパイラーが単純なポストインクリメントをプレインクリメントに置き換えることを決定できることです。これによってコードが変わることはありません。

0
Colin Hebert

インクリメントは独立したステートメントとして実行されます。そう

y--;

そして

--y;

互いに同等であり、両方とも同等です

y = y-1;

0
Ken Paul

これは:

int x = 2;
for (int y =2; y>0; y--){
    System.out.println(x + " "+ y + " ");
    x++;
}

コンパイラによって効果的に次のように変換されます。

int x = 2;
int y = 2
while (y > 0){
    System.out.println(x + " "+ y + " ");
    x++;
    y--;
}

ご覧のとおり、y--または--yを使用しても違いはありません。ただし、次のようにループを作成すると、違いが生じます。

int x = 2;
for (int y = 3; --y > 0;){
    System.out.println(x + " "+ y + " ");
    x++;
}

これにより、ループの2つのバリアントと同じ結果が得られますが、ここで--yからy--に変更すると、プログラムが破損します。

0
gustafc

I ++(ポストインクリメント)と++ i(プレインクリメント)について@me: "どちらの場合も、式が評価され、その結果を使用して条件をチェックします。プレインクリメントの場合、インクリメント式は変数をインクリメントし、結果の値を返します。ポストインクリメントの場合、インクリメント式も変数をインクリメントしますが、前の値を返します。その結果、プリインクリメントはインクリメントされた値と比較され、ポストインクリメントは元の値。どちらの場合も、条件がチェックされると変数がインクリメントされます。」 – tdammers

0
Wolfpack'08

ポストインクリメント演算子とプリインクリメント演算子の間にはかなりの混乱があります。これは、この「アルゴリズム、ロバートセッジウィックとケビンウェインによる第4版」の抜粋から簡単に理解できます。

インクリメント/デクリメント演算子:i ++はi = i + 1と同じであり、式に値iがあります。同様に、i--はi = i-1と同じです。コード++ iと--iは同じですが、式の値がインクリメント/デクリメントの前ではなく後に取得される点が異なります。

例えば

x = 0; 
post increment:
x++;
step 1: 
assign the old value (0) value of the x back to x.So, here is x = 0.
step 2:
after assigning the old value of the x, increase the value of x by 1. So,
x = 1 now;

when try to print somthing like:
System.out.print(x++);
the result is x : 0. Because only step one is executed which is assigning 
old value of the x back and then print it.

But when, we do operation like this: 
i++;
System.out.print(i);
the result is x: 1. which is because of executing Step one at first 
statement and then step two at the second statement before printing  the 
value.

pre increment:
++x;
step 1: 
increase the value of x by 1. So, x = 1 now;
step 2:
assign the increased value back to x.

when try to print something like:
System.out.print(++1)  
the result is x : 1. Because the value of the x is raised by 1 and then 
printed. So, both steps are performed before print x value. Similarly, 
executing 
++i;
system.out.print(i);
Both steps are executed at statement one. At second statement, just the 
value of "i" is printed.
0
Irfan Ul Haq

Stackoverflowには同様の投稿がたくさんあります。

ただし、どの言語やコンパイラにも固有ではないため、質問はより一般的であるように思われます。上記の質問のほとんどは、特定の言語/コンパイラを扱っています。

要約は次のとおりです。

  • c/C++/Java(おそらくC#も)と最新のコンパイラについて話している場合:
    • iが整数の場合(const intintなど):
      • 次に、コンパイラは基本的にi++++iに置き換えます。これは、これらが意味的に同一であり、出力を変更しないためです。これは、生成されたコード/バイトコードをチェックすることで確認できます(Javaの場合、 jclasslibバイトコードビューア を使用します)。
    • そうしないと:
  • そうしないと:
    • コンパイラーはそれらが意味的に同一であることを保証できないため、すべての賭けはオフになり、最適化を試みません。

したがって、C++に、接尾辞と接頭辞の演算子(std::iteratorなど)をオーバーライドするクラスがある場合、この最適化が行われることはほとんどありません。

要約すれば:

  • あなたが言うことを意味し、あなたが意味することを言いなさい。 forループのインクリメント部分では、ほとんどの場合、プレフィックスバージョン(つまり、++i)が必要です。
  • ++ii++の間のコンパイラの切り替えは、常に実行できるとは限りませんが、可能であれば、それを実行しようとします。
0
The Alchemist

ループでは、最初に初期化、次に条件チェック、次に実行、その後インクリメント/デクリメントします。したがって、プリ/ポストインクリメント/デクリメントはプログラムコードに影響を与えません。

0
alfesani

それらは同じように動作しません。 i ++の構成は、++ iの構成よりもわずかに遅くなります。これは、前者がiの古い値と新しい値の両方を返す必要があるためです。一方、後者はiの古い値のみを返します。

次に、おそらくコンパイラは少し魔法をかけ、パフォーマンス上の理由から、分離されたi ++++ iに変更しますが、生のアルゴリズムに関しては、厳密には同じではありません。

0
rewritten

あなたが正しいです。この場合、違いがわかります。

for(int i = 0; i < 5; )
       {
            System.out.println("i is : " + ++i);           
       }
0
Piotr Müller

それは好みの問題です。彼らは同じことをします。

Javaクラスのコードを見ると、ポストインクリメントのforループがあります。

0
Roman

あなたの場合、それは同じで、まったく違いはありません。

0
manuel

はい、順番に行います。初期化、次に評価条件、そしてtrueの場合、本体を実行してからインクリメントします。

プレフィックスとポストフィックスの違いは、インクリメント/デクリメントを使用して割り当て操作を実行した場合にのみ顕著になります。

0
Mohib Sheth