次のforループは、ポストインクリメントと他のプリインクリメントを使用しても同じ結果をもたらします。ここで'for'ループ内のポストインクリメントとプリインクリメントは同じ出力を生成します
は、コードは次のとおりです。
for(i=0; i<5; i++) {
printf("%d", i);
}
for(i=0; i<5; ++i) {
printf("%d", i);
}
私はループ「の」両方に同じ出力を得ます。何か不足していますか?
次のforループは、ポストインクリメントと他のプリインクリメントを使用しても同じ結果をもたらします。ここで'for'ループ内のポストインクリメントとプリインクリメントは同じ出力を生成します
は、コードは次のとおりです。
for(i=0; i<5; i++) {
printf("%d", i);
}
for(i=0; i<5; ++i) {
printf("%d", i);
}
私はループ「の」両方に同じ出力を得ます。何か不足していますか?
i++
または++i
を評価した後、新しい値i
はどちらの場合も同じになります。プリインクリメントとポストインクリメントの違いは、式自体を評価した結果です。
++i
増分i
となり、新しい値はi
と評価されます。
i++
は、古い値がi
であり、増分がi
となります。
これはループのために重要ではありません。その理由は、制御の流れは、おおよそ次のように動作することである:それがfalseの場合、それがある場合
を実行し、(4)のいずれかの前または後INCR、切り離される
はい、両方の出力がまったく同じになります。なぜ彼らはあなたに異なる出力を与えるべきだと思いますか?
ポストインクリメントまたはこのような状況では、プリインクリメント事項:あなたが割り当てることによって、または引数を渡すことで、どちらかの、いくつかの価値を提供
int j = ++i;
int k = i++;
f(i++);
g(++i);
。 for
ループではどちらも行いません。それはインクリメントされるだけです。ポストとプレは意味がありません!
どちらの場合も、増分はループの本体の後に行われるため、ループの計算には影響しません。コンパイラが愚かであれば、ポストインクリメントを使用するほうが効率的ではないかもしれません(後で使用するために通常はの前のの値のコピーを保持する必要があるため)。この場合、 。
どのようにforループが実装され、基本的に割り当て、テスト、および分岐命令のセットに変換されるか考えるのは便利かもしれません。擬似コードでは、プリインクリメントは次のようになります。
set i = 0
test: if i >= 5 goto done
call printf,"%d",i
set i = i + 1
goto test
done: nop
ポストインクリメントは、少なくとも別のステップを持っているでしょうが、離れて
set i = 0
test: if i >= 5 goto done
call printf,"%d",i
set j = i // store value of i for later increment
set i = j + 1 // oops, we're incrementing right-away
goto test
done: nop
私は++と++私も最適化するために、些細なことだろうprintf( "%d"、i)が毎回実行された後に実行されるため、違いはありません。
これは簡単です。上記for
ループは、線i++;
と++i;
は、コードブロックの観点から同じ意味を持っていることを注意
int i = 0;
while(i < 5) {
printf("%d", i);
i++;
}
と
int i = 0;
while(i < 5) {
printf("%d", i);
++i;
}
と意味的に等価です。両方とも、i
の値に同じ効果を持ちます(1つ増分する)ので、これらのループの動作にも同じ効果があります。ループはこのコードj
の最初のブロックにインクリメント後i
の値を見ているからである(i
を最初にインクリメント、またはプレさ
int i = 0;
int j = i;
while(j < 5) {
printf("%d", i);
j = ++i;
}
int i = 0;
int j = i;
while(j < 5) {
printf("%d", i);
j = i++;
}
ように書き換えた場合に差が存在するであろうこと
注インクリメンタルなので、名前)と、コードの第2ブロックj
は、インクリメントの前にi
の値を見ます。
別のものが発生する可能性があることを説明するニースの答え! Upvote :) –
コンパイラは、あなたのケース(ポスト/プリインクリメント)中のSO
a;
while(b)
{
...
end:
c;
}
に
for (a; b; c)
{
...
}
を翻訳し、それは問題ではありません。
EDITは:単純にこれは私のお気に入りのインタビューの質問の一つであるgoto end;
実際には、それはかなり正しくはありません。 'for(int i = 0; i <42; i ++){printf("%d "、i);}を見てください。持続する; } '例えば。あなたの主張は、それは意味的に 'int i = 0;と同じです。 while(i <42){printf( "%d"、i);持続する;私は+ +; } 'それは明らかに間違っています。 – jason
私の編集を参照してください。この声明は私のものではなく、私がよく覚えていればコンパイラについて読んだ本からです。この本はhttp://www.amazon.com/Compilers-Principles-Techniques-Alfred-Aho/dp/0201100886でした。 – jdehaan
私はそれがドラゴンの本のような間違いを疑う。いずれにしても、もう少し注意深い読みが順調でしょうか? – jason
に置き換えられ続けます。最初に答えを説明し、なぜ私は質問が好きなのかを説明します。
ソリューション:
答えが包括的、両方のスニペットは、0から4までの数字を印刷しておくことです。 for()
ループは、一般的にwhile()
ループに相当しますので、これは次のとおりです。
for (INITIALIZER; CONDITION; OPERATION) {
do_stuff();
}
を書き込むことができます:
INITIALIZER;
while(CONDITION) {
do_stuff();
OPERATION;
}
あなたは操作がループの一番下で行わ常にであることがわかります。この形式では、i++
と++i
が同じ効果を持つことが明らかです。これらは両方ともインクリメントi
であり、結果は無視されます。 i
の新しい値は、ループの先頭で次の反復が始まるまでテストされません。
編集:ループがwhile()
ループ内で実行されてからOPERATION
を防止するであろう(例えばcontinue
など)制御文が含まれている場合、このfor()
while()
に同値がないホールドをしていることを指摘してジェイソンのおかげで。OPERATION
は、for()
ループの次の反復の直前に実行されると常にであるです。
、それはすべての
最初の質問良いインタビューだなぜ、候補者は、すぐに正しい答えを伝える場合にのみ2分かかりますので、私たちは次の質問に右に移動することができます。
しかし、驚くべきことに、多くの候補者は、ポストインクリメントのループでは0から4までの数字が出力され、プリインクリメントループでは0から5、または1から5が出力されますプリインクリメントとポストインクリメントの違いを正しく説明していますが、ループのメカニズムを誤解しています。
その場合、私はwhile()
を使ってループを書き直すように頼んでいます。これは本当に私の思考プロセスの良いアイデアです。それで私は最初に質問をします。彼らの問題へのアプローチと、世界の動向に疑問を投げかけたときの進捗状況を知りたいのです。
この時点で、ほとんどの候補者はエラーを認識し、正しい答えを見つけます。しかし、元の答えが正しかったと主張して、for()
をwhile()
に翻訳した方法を変更しました。それは魅力的なインタビューのために作られましたが、私たちはオファーをしませんでした!
希望に役立ちます!
あなたは重大だが一般的な間違いをしたので、このインタビューの質問を再検討する必要があります。 'for'ループは、あなたが一般的に指定したように書き直すことはできません。 'for(int i = 0; i <42; i ++){printf("%d "、i);}を見てください。持続する; } '例えば。あなたの主張は、 'int i = 0;と意味的に同等であるということです。 while(i <42){printf( "%d"、i);持続する;私は+ +; } 'それは明らかに間違っています。 – jason
@Jason:今日は、私が考慮していなかったエッジケースを学びました!ほぼ10年のうちに、私は候補者にこれを認識させることはなかった。私が言及した理由のために貴重なこの質問を引き続き使用するならば、私は上記の編集ごとにそれを言い換えてください。候補者が正解をすぐに提示した場合は、例外があるかどうかを尋ねます。あなたの明確な反例のために:-) +1。ありがとうございました! –
@Jason、私は何かを紛失している、またはあなたの質問に対する回答が同じではない。 @アダム・リス、私はあなたの声明の中で正しいと思います、私の答えの補足を見てください。実際には、継続を非常に簡単に実装することもできます。 – jdehaan
場合に違いがあります:
int main()
{
for(int i(0); i<2; printf("i = post increment in loop %d\n", i++))
{
cout << "inside post incement = " << i << endl;
}
for(int i(0); i<2; printf("i = pre increment in loop %d\n",++i))
{
cout << "inside pre incement = " << i << endl;
}
return 0;
}
結果:= 0
ポストincement内部
= 1
ポストincement内部ループ0におけるI =ポストインクリメント
i =ループ1のポストインクリメント
0 forループ秒:予備incement内部
= 0
I =ループにおけるプリインクリメント1
事前incement内部= 1
I =ループにおけるプリインクリメント2
この違いはforループとは無関係です。これは、ステートメントに副作用がある場合にプリ/ポストインクリメントを使用しているためです。 –
for構文の3番目の文は実行されますが、評価された値は破棄され、処理されません。
評価値が破棄されると、前と後のインクリメントは等しくなります。
値が異なる場合にのみ異なります。
コードの結果は同じになります。その理由は、2つのインクリメント操作が2つの別個の関数呼び出しであると見ることができるからです。どちらの関数も変数のインクリメントを引き起こし、戻り値のみが異なります。この場合、戻り値はただ破棄されます。つまり、出力には違いがありません。フード違いがあります下しかし
、:からi++
ニーズがi
の元の値を格納する一時変数作成ポストインクリメントは、その後インクリメントを実行し、一時的な変数を返します。事前インクリメント++i
は、一時変数を作成しません。確かに、オブジェクトがint
のような単純なものであれば、適切な最適化設定はこれを最適化できるはずですが、++演算子はイテレータのような複雑なクラスでオーバーロードされることに注意してください。 2つのオーバーロードされたメソッドは異なる操作を持つ可能性があります(たとえば、 "Hey、I'll pre-incremented!"をstdoutに出力することがあります)、コンパイラは戻り値が使用されていないとき(基本的にこのようなコンパイラは解決不可能なhalting problemを解決するため)、myiterator++
と書くと、より高価なポストインクリメントバージョンを使用する必要があります。あなたはインクリメントを事前すべき理由
3つの理由:
私はあなたが間違っていると思います! ++ iとi ++の唯一の違いは、あなたが行うことの順序です。あなたは 株式会社*私は*私 を押し なり、他にあなたが プッシュ*私は 株式会社*私 私はこの最適化をconciderはないでしょう1の場合 。 –
彼は間違っていません。ポストインクリメントプリミティブは、コピーを使用しないときにコンパイラによって非常に簡単に最適化されます。しかし、最後のビットで言及している点は、イテレータのポストインクリメントがメソッド呼び出しとイテレータの全く新しいコピーの構築として実装されていることです。コンストラクタと関数呼び出しは、コンパイラが追跡できない副作用を持つ可能性があるため、これらは重要ではないと想定できないため、コンパイラによって最適化することはできません。 – Jherico
>あるケースでは私は* iを押し込み、もう1つは* i inc * iを押すでしょう。私はこれを最適化しないでしょう。 – user3697618
あなたはこのようにそれを書いた場合、問題になります。
for(i=0; i<5; i=j++) {
printf("%d",i);
}
が複数回を繰り返すだろう。このように書かれている場合:あなたはそれのために、Googleの答えを読むことができた
for(i=0; i<5; i=++j) {
printf("%d",i);
}
ここでは: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Preincrement_and_Predecrement
したがって、主な点は、単純なオブジェクトでは何の違いもありませんが、 rイテレータおよびその他のテンプレートオブジェクトを使用する必要があります。
EDITED:あなたはループ本体の後に実行シンプルなタイプなので、副作用なし、と後またはpreincrements、ループ本体内の値にそれほど影響を与えずに使用しているため
差はありません。
あなたは、このようなループでそれをチェックすることができ:
for (int i = 0; i < 5; cout << "we still not incremented here: " << i << endl, i++)
{
cout << "inside loop body: " << i << endl;
}
これは出力が同じ理由についての質問には答えません。 –
@ボ・ペルソン、公平であるためには、私の答えだけでなく、そのような印を付けるべきです。私はあなたが本当に失礼だと思う。 – Yola
私は多分、他の答えは2歳で、実際には答えてみる* "違いがない理由を知りたい" *。 –
増分がクラスに呼び出されたときの動作はあまり異なる場合がありますから、それは、非同等ポストまたはプリインクリメントを呼び出すことになるかもしれません。 – mbaitoff
'i ++'と '++ i'の間に構文的な違いがない場合、なぜ' ++ i'を使う人が見えますか?フードの下であっても、*相違はありますか? –
'i ++'がインクリメント後に 'i'の古い値を記憶する必要があることを考えれば、' ++ i'はもっと短くてもよい(1-2命令のオーダー)。 – danben