C ++ forループの前には見たことがない


164

C ++アルゴリズムをC#に変換していました。私はこのforループに出くわしました:

for (u = b.size(), v = b.back(); u--; v = p[v]) 
b[u] = v;

C ++ではエラーは発生しませんが、C#ではエラーが発生します(intをboolに変換できません)。このforループが本当にわかりません。条件はどこにありますか?

誰か説明していただけますか?

PS。チェックのために、ベクトルをリストに適合させるために、b.back()はb [b.Count-1]に対応していますか?


35
状態はどこですか?それはだろうu--。セミコロンは、forステートメントのさまざまな部分を区切るために使用されます。
デビッドヘファーナン

77
これは非常に正常なループです。あなたに条件を有効にする必要がありますので、C#が暗黙のうちにboolsに番号を変換しません; u-- != 0;
R.マルティーニ・フェルナンデス

28
@ジェシー・グッド-良いコードは、言語で許可されていることとは何の関係もありません。無制限の同僚がコードを読み取るのにかかる時間に関係しています。それが何らかの混乱を引き起こす場合、たとえそれが合法であっても、それは可能な最良の解決策ではありません。多くの場合、より詳細なソリューションの方が簡潔なソリューションよりもはるかに優れており、ほとんどのコンパイラはどちらの方法でも同じものにコンパイルされます。
Bill K

18
私は、コードを変換した後、あなたが変数により良い名前を与え、それを願ってbuv、など、誰かが自分のコードが読めないことによって、スマートに見えると思ったので、彼らはこのように命名した唯一の理由はあるが。
Dan

33
@houbysoft:これは一般的なスタックオーバーフローの問題です。特定の研究領域で非常に詳細でよく研究された興味深い質問をすると、それは難しい興味深い問題の解決につながり、そのような質問に答えるのに、数日分の研究が必要になります。数十人の訪問者と、フィールドの数人の専門家からの1つまたは2つの賛成票。多くの担当者をすばやく獲得したい場合は、このような質問をして答える必要があります。「PHPで2つの数値を追加するにはどうすればよいですか」、「doC ++で何を意味するか」-チュートリアルを探している初心者から何千ものヒットを取得します。
vsz 2012

回答:


320

forループの状態は、2つのセミコロンの中間にあり;ます。

C ++では、ほとんどすべての式を条件として指定できfalseます。ゼロに評価されるものはすべて、非ゼロはを意味しtrueます。

あなたの場合、条件はu--次のとおりです:C#に変換するとき、単に追加し!= 0ます:

for (u = b.size(), v = b.back(); u-- != 0; v = p[v]) 
    b[u] = v; //                     ^^^^ HERE

55
ちなみに、トーマスはコンマの使用に混乱している可能性があります。セミコロンとは非常に異なり、forループの1つのセクションで複数のことを実行できます(この場合、2つの変数を初期化します)。前回私がこれらの異常な構造をチェックしたときは、可能な最も読みやすいソリューションとは考えられなかったため、一部の人には不快に思われるかもしれません。
ビルK

2
私が正しく覚えていて、コンマを含む式には、右側の最後の部分式の値があります。これはCに由来し、forループだけでなく、あらゆる式で使用できます。
ジョルジオ

7
@Rogerこれはループの最初ではなく(つまり、b [u] = vの後ではなく)ループの終わりでuを減らすので、同じループにはなりません。実際には、u = b.size() - 1代わりにで初期化する必要があります。
Didier L

Fyi:500Kの制限を超えました。それはどこかで100万番目の顧客であり、どこかで勝っているようなものですか?いずれにしても:おめでとうございます。常にあなたの正確で鋭い答えを見上げてください!立ち止まるな; 100万のものを作ってあなたに会います...今世紀後半。
GhostCat

165

正確な答えはたくさんありますが、同等のwhileループを書く価値はあると思います。

for (u = b.size(), v = b.back(); u--; v = p[v]) 
   b[u] = v;

以下と同等です。

u = b.size();
v = b.back();
while(u--) {
   b[u] = v;
   v = p[v];
}

C#に変換するときは、while()形式にリファクタリングすることを検討してください。私の意見では、それはより明確であり、新しいプログラマにとってのわなのではなく、同等に効率的です。

他の人が指摘したように-しかし、私の答えを完全にするために-C#で機能させるには、に変更while(u--)する必要がありますwhile(u-- != 0)

...またはwhile(u-- >0)uが負から始まる場合に備えて。(OK、b.size()決して否定的ではありません-しかし、おそらく他の何かがuを初期化した一般的なケースを検討してください)。

または、さらに明確にするために:

u = b.size();
v = b.back();
while(u>0) {
   u--;
   b[u] = v;
   v = p[v];
}

簡潔にするよりも、明確にする方がいいです。


29
この回答は、不正なコードを明確にするだけでなく、優れた代替策も提供します。1アップ!!
polvoazul 2012

2
余談ですが、私はwhile (u-- >0)フォームに注意します。間隔がめちゃくちゃになると、「ゼロまで」のループになってしまう可能性があります。 while (u --> 0)これは、一目ですべてのユーザーを混乱させる傾向があります。(それが有効なC#であるかどうかは
わかり

9
私はあなたのコードが必ずしもより明確であるとは思いません。for代わりにのポイントはwhile、初期化とインクリメント/デクリメントを1つのステートメントに配置することであり、必ずしもコードを理解しにくくするわけではありません。それ以外の場合は、使用すべきではありませんfor
musiphil 2012

1
また、できるだけ少ないコードを書き直すことも重要です。(結局のところ、forループは変わる可能性があります。) "u--"を2つの別々の場所に配置したため、ループがあまり明確ではありません(forループの機能を一目で確認できます。スキャンする必要があります。複数行あり)。簡潔であることには利点もあります。それらを軽視しないでください。それでも、他にどのように書くことができるかの良い例です。これにより、C ++のステートメントに慣れていない人(またはおそらくまったくそうでない人)も理解しやすくなります。
NotKyon

2
@Izkata:決して演算子ではなく、--トークンの後にトークンとして解析され>ます。2つの別個の演算子。「ゼロまで」ループは、ポストデクリメントとより大きいの単純な組み合わせです。C ++演算子のオーバーロードでは、新しい演算子は作成されません。既存の演算子が再利用されるだけです。
Ben Voigt

66

for命令のu--;2番目の位置にあるため、条件はです。

の値がu--;0と異なる場合は、解釈されますtrue(つまり、暗黙的にブール値にキャストされますtrue)。代わりに、その値が0の場合、にキャストされfalseます。

これは非常に悪いコードです。

更新:このブログ投稿で「for」ループの作成について説明しました。その推奨事項は次の段落に要約できます。

forループは実用的で読みやすく(慣れれば)簡潔な構成ですが、うまく使用する必要があります。その一般的ではない構文のため、想像力に富んだ方法で使用することはお勧めできません。

forループのすべての部分は短く、読みやすくする必要があります。変数名は、わかりやすくするために選択する必要があります。

この例は明らかにこれらの推奨事項に違反しています。


3
または、u == 0で停止するでしょう...?
トーマス

2
番号; C ++では、intからboolへの暗黙的な変換があり、0はfalseに変換されます。ループは、u-- == 0のときに終了します。C#では、そのような暗黙の変換は行われないため、u-- == 0と明示的に言う必要があります。編集:これは、最初のコメントに対する応答です。
クリス

48
これは非常に単純な理由でひどいコードです。あなたがそれを読んだとき、あなたはそれを簡単に理解することができませんでした。それは「賢い」、「ハック」です。それは、コーディング構造の組み合わせと、それらが舞台裏でどのように機能するかについての知識を利用して、機能はしますが、理解を妨げる構造を作成します。言語ユーザー。
KeithS 2012

4
すばらしい答えです。私はそれを+1します...そうでない場合は、「これは非常に悪いコードです」。ステートメント;)
Sandman4 2012

14
なぜ多くの人がu--が(C ++に暗黙的に)欠けているために本当に悪いコードであると考えるのか理解できません!!= 0。確かに、コードを扱う誰もが0 = false、その他すべてのvalue = trueに完全に気づいているでしょう。uの前/後のインクリメントに関する混乱の余地ははるかにあります、またはおそらくu = b.size()常にv = b.back()の前に実行されると想定している人々(私の理解では、実行シーケンスは未定義ですが、しかし、私は修正される立場にあります)。
FumbleFingers

23

これがループのC#形式になります。

// back fetches the last element of vector in c++.
for (u = b.size(), v = b.back(); (u--) != 0; v = p[v]) 
{      
  b[u] = v;      
}

size()とback()の同等のものを置き換えるだけです。

これは、リストを逆にして配列に格納します。しかし、C#では、このためのシステム定義関数を直接持っています。したがって、このループを記述する必要もありません。

b = b.Reverse().ToArray();

1
とることでv = b.back();あるため、あなたはそれが動作する方法を変更していないため初期化子のうちv = p[v]で上書きされる
ジョアン・ポルテラ

v = p [v]は、この行が最後に実行されるため、最終結果に影響を与えません。その後、vはループで参照されません。この行は、ループがC ++からC#に変換される方法を示すためだけにあります。
Narendra

1
c ++コードでv = b.back();は、反復が始まる前に1回v = p[v]実行され、各反復の開始時に実行されました。そのC#バージョンでv = p[v]は、各反復の開始時に引き続き実行されますが、そのv = b.back();直後に実行さvれ、次の命令の値を変更しますb[u] = v;。(あなたがそれを読んだ後、多分質問が編集された)
ジョアン・ポルテラ

5
@Rain問題はv = b.back()です。あなたはそれだけではなく、最初の1のすべてのループの繰り返しで実行する必要があります-私たちは何を知らないback()ん(任意の副作用があり、それはの内部表現を変更していますか?b、このループがあるので?)ではないの1に相当質問。
イズカタ2012

1
@Rain正確に、自分でよく見てください。初期化ループが始まる前のステップは、一度だけ起こっていないの初めにすべての反復v = b.back()ループの外、その上に移動された場合、コードは正しいでしょう。(また、誰かに返信しようとしている場合@は、その名前の前で使用して、通知を受け取ります)
Izkata


14

条件はの結果ですu--。これは、u減少する前の値です。

CおよびC ++では、int ある暗黙的に実行して、ブール値に変換!= 0比較を(0であるfalse、他のすべてがありますtrue)。

b.back()あるコンテナ内の最後の要素ですb[b.size() - 1]size() != 0


11

C trueでは、ゼロ以外のすべては、ループの終了条件や条件ステートメントなどの「ブール」コンテキストにあります。C#では、そのチェックを明示的にする必要がありますu-- != 0


これはOPの問題ではありません。彼は、最終状態の評価(つまり、この場合は「u--」)について尋ねています。
ApplePie

6

他の人が述べたように、C ++がブール値への暗黙のキャストを持っているという事実は、条件がu--であることを意味します。これは、値がゼロ以外の場合に真になります。

「条件はどこにあるのか」を尋ねる際に誤った仮定があることは、追加する価値があります。C ++とC#の両方(および他の同様に構文化された言語)では、空の条件を使用できます。この場合、常にtrueと評価されるため、ループは永久に、または他の条件が(、、またはを介してreturn)終了するまで続きます。breakthrow

for(int i = 0; ; ++i)
  doThisForever(i);

実際、forステートメントのどの部分も省略できます。その場合、実行されません。

一般的に、for(A; B; C){D}または次のようにfor(A; B; C)D;なります。

{A}
loopBack:
if(!(B))
  goto escapeLoop;
{D}
{C}
goto loopBack;
escapeLoop:

A、B、C、Dのいずれか1つ以上を省略することができます。

この結果として、for(;;) 無限ループを好む人もいます。私while(true)はそれがより人気がある一方で、「真実が真実になるまで」と読んだためfor(;;) です。

それは好みの問題ですが、私が好きなのは私だけではないので、for(;;)それが何を意味するのかを知る価値があります。


4

すべての答えは正しいです:-

forループは、次のようにさまざまな方法で使用できます。

Single Statement inside For Loop
Multiple Statements inside For Loop
No Statement inside For Loop
Semicolon at the end of For Loop
Multiple Initialization Statement inside For
Missing Initialization in For Loop
Missing Increment/Decrement Statement
Infinite For Loop
Condition with no Conditional Operator.

4
for (u = b.size(), v = b.back(); u--; v = p[v]) 
   b[u] = v;

上記のコードでは、uおよびvで初期化されb.size()ていb.back()ます。

条件がチェックされるたびに、デクリメントステートメントも実行されますu--

forループは終了しますuとなります0


3

C#自体で発生したエラーは疑いを解消します。forループは、

終了する条件。そして、私たちが知っているように、

(ブール)FALSE =(int)0

ただし、C#は、C ++とは異なり、これを単独で処理することはできません。だからあなたが探している状態は

u--

しかし、あなたは明示的にC#で条件を与える必要があります

u--!= 0

または

u--> 0

しかし、それでもこの種のコーディング慣行は避けてください。の

ループ

上記の回答で述べたのは、

forループ。


@Downvoter:解決策に満足しない限り、投票に問題はありませんが、回答を改善できるように、理由を説明してください。
Abhineet 2013年

3

C / C ++に慣れている場合、このコードは読みにくいものではありませんが、かなり簡潔で、それほど優れたコードではありません。だから、私が何よりもシスムである部分を説明させてください。まず、C forループの一般的な構文は次のようになります。

for (<initialization> ; <condition>; <increment>)
{
    <code...>
}

初期化コードは1回実行されます。次に、条件はすべてのループの前にテストされ、最後にすべてのループの後に増分が呼び出されます。したがって、あなたの例では、条件がu--

なぜu--C#ではなくCの条件として機能するのですか?Cは暗黙のうちに多くのことを暗黙のうちに変換してしまうので、問題を引き起こす可能性があります。数値の場合、ゼロ以外のものはすべて真であり、ゼロは偽です。したがって、b.size()-1から0までカウントダウンします。条件に副作用があることは少し厄介であり、forループのインクリメント部分に配置することをお勧めします。コードはこれを行います。私がそれを書いているなら、私は次のようにそれをするでしょう:

for (u = b.size() - 1, v = b.back(); u>=0; --u) 
{
    b[u] = v;
    v = p[v]
}

これの理由は、少なくとも私には、それはより明確です。forループの各部分は、それだけで機能します。元のコードでは、条件は変数を変更していました。インクリメント部分は、コードブロックなどにあるはずのことをしていました。

カンマ演算子は、ループのためにもあなたを投げているかもしれません。C x=1,y=2では、コンパイラに関する限り、ステートメントは1つのステートメントのように見え、初期化コードに適合します。単に各パーツを評価し、最後のパーツの値を返します。だから例えば:

std::cout << "(1,2)=" << (1,2) << std::endl;

印刷されます2。


書き換えの問題は、b.size()が署名されていない場合、非常に長い間繰り返されることです。(また、セミコロンが欠落しています。)しかし、少なくとも「ディックとジェーンは英語が上手い」というアプローチをとっていなかったため、他の多くの回答やコメントがそうであったように、不合理に冗長な書き直しを簡単に歓迎しています。初心者やその他の非熟練プログラマーが読むこと。
ジムバルター2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.