web-dev-qa-db-ja.com

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

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

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

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

誰か説明してもらえますか?

PS。チェックするだけで、VECTORをLISTに適合させるために、b.back()はb [b.Count-1]に対応しますか?

163
Thomas

forループの条件は、中間-2つのセミコロン;

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

あなたの場合、条件はu--:C#に変換するときは、単に!= 0

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

正確な答えはたくさんありますが、同等の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()形式へのリファクタリングを検討することもできます。私の意見では、それはより明確で、新しいプログラマーにとってのtrapではなく、同様に効率的です。

他の人が指摘したように-しかし私の答えを完全にするために-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];
}
_

簡潔であるよりも明確である方が良いです。

165
slim

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

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

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

更新:これで「for」ループの記述について議論しました ブログ投稿 。その推奨事項は、次の段落で要約できます。

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

Forループのすべての部分は短く、読みやすいものでなければなりません。変数名は、理解しやすいように選択する必要があります。

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

65
Daniel Daranas

これはループの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();
23
Narendra

条件は_u--_の結果です。これは、デクリメントされる前のuの値です。

CおよびC++では、intis暗黙的に_!= 0_比較を実行することでブールに変換可能(0はfalseで、その他はすべてtrue)。

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

14
Bo Persson
u = b.size(), v = b.back()

初期化です。

u--

条件です。

v = p[v]

繰り返しです

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

11
Joey

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

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

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(;;)が好きなのは私だけではないので、それが何を意味するかを知る価値があります。

6
Jon Hanna

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

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
birubisht
_for (u = b.size(), v = b.back(); u--; v = p[v]) 
   b[u] = v;
_

上記のコードでは、uvb.size()b.back()で初期化されます。

条件がチェックされるたびに、デクリメントステートメントも実行されます(つまり、_u--_)。

forが_0_になると、uループは終了します。

4
Apte

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

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

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

どして u-- C#ではなくCの条件として機能しますか? Cは暗黙的に多くのものを変換するのであまりにもboolであり、問​​題を引き起こす可能性があるためです。数値の場合、ゼロ以外の値はすべて真であり、ゼロは偽です。そのため、b.size()-1から0にカウントダウンします。条件に副作用があることは少し面倒であり、Cの多くはコードはこれを行います。私がそれを書いていたら、私はもっとこのようにします:

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。

3
Matt Price

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

FALSE

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

(ブール)FALSE =(整数)0

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

うー

ただし、C#で条件を明示的に指定する必要があります

u--!= 0

または

u--> 0

ただし、この種のコーディング慣行は避けてください。の

whileループ

上記の答えは、あなたの最も単純化されたバージョンの1つです

forループ。

3
Abhineet