web-dev-qa-db-ja.com

符号なしインデックスで逆forループを実行する最良の方法は何ですか?

reverse for loopの私の最初の試みは、何かをn回行います:

for ( unsigned int i = n-1; i >= 0; i-- ) {
    ...     
}

この失敗では、符号なし算術iは常にゼロ以上であることが保証されているため、ループ条件は常に真になります。幸いなことに、gccコンパイラは、ループが無限に実行されている理由を疑問に思う前に、「無意味な比較」について警告しました。


この問題を解決するエレガントな方法を探しています。

  1. ループの後方にある必要があります。
  2. ループインデックスは符号なしである必要があります。
  3. nは符号なし定数です。
  4. 符号なし整数の「あいまいな」リング演算に基づいてはなりません。

何か案は?ありがとう:)

56
Auron

どうですか:

for (unsigned i = n ; i-- > 0 ; )
{
  // do stuff with i
}
94
Skizz
for ( unsigned int loopIndex = n; loopIndex > 0; --loopIndex ) {
    unsigned int i = loopIndex - 1;
    ...
} 

または

for ( unsigned int loopIndex = 0; loopIndex < n; ++loopIndex ) {
    unsigned int i = n - loopIndex - 1;
    ...
} 
12
Lou Franco
for ( unsigned int i = n; i != 0; i-- ) {
    // do something with i - 1
    ...     
}

CだけでなくC++を使用する場合、!=を使用することは、イテレータの使用に切り替えるときに慣れる良い習慣であることに注意してください(<=などは使用できない場合があります)。

11
anon

なぜ単純ではない:

unsigned int i = n;
while(i--)
{ 
    // use i
}

これは、質問の本文に列挙されているすべての要件を満たしています。コードレビューに失敗したり、コーディング標準に違反したりする可能性のあるものは使用しません。私が見ることができる唯一の異論は、OPが本当にforループを主張し、i =(n-1).. 0を生成する直接的な方法ではない場合です。

9
idz
for ( unsigned int i = n; i > 0; i-- ) {
    ...  
    i-1 //wherever you've been using i   
}
8
vartec

使用する傾向がある

 for ( unsigned int i = n; i > 0; )  {
    --i;
    ...     
 }

これは、skizzの答えとほぼ同じであり(最終的な不必要なデクリメントを逃しますが、コンパイラはそれを最適化する必要があります)、実際にコードレビューに合格します。私が取り組まなければならなかったすべてのコーディング標準には、条件付きルールに変化がありませんでした。

8
Pete Kirkham

たぶんこのように?私見は明確で読みやすい。暗黙的に既知のif(n> = 1)は省略できます。

if(n>=1) {
    // Start the loop at last index
    unsigned int i = n-1;
    do {
       // a plus: you can use i, not i-1 here
    } while( i-- != 0 );
}

別のバージョン:

if(n>=1) {
    unsigned int i = n;
    do {
       i--;

    } while( i != 0 );
}

Ifステートメントのない最初のコードは次のようになります。

unsigned int i = n-1;
do {

} while( i-- != 0 );
5
anon
for (unsigned int i = n-1; i<(unsigned int)-1; i--)

OK、その「あいまいなリング演算」。

4
Eric Bainville

または、n-1から0へのインデックス付けが必要な場合は、unsigned intのラッピング動作に依存できます。

for(unsigned int i = n-1; i < n; i--) {
    ...
}
4
peje
for ( unsigned int i = n; i > 0; i-- ) {
    unsigned int x = i - 1;
    // do whatever you want with x    
}

確かにエレガントではありませんが、機能します。

3
itsmatt

このオプションに言及する唯一の理由は、リストに表示されていないためです。

for ( unsigned int i = n-1; i < n; i-- ) {
... 
}

完全に直感に反しますが、機能します。動作する理由は、0から1を引くと、符号なし整数で表現できる最大数が得られるためです。

一般に、特に減算の場合、符号なし整数とアーティメットを使用するのは良い考えではないと思います。

3
Renze de Waal

簡単、-1で停止:

for( unsigned int i = n; i != -1; --i )
{
 /* do stuff with i */
}

編集:なぜこれがダウン投票されているのか分かりません。それは機能し、上記のどれよりも簡単で明白です。

2
Dave
for ( unsigned int i = n; i > 0; i-- ) {
    ...     
}

正常に動作するはずです。 i変数を配列のインデックスとして使用する必要がある場合は、次のようにします。

array[i-1];
1
arul

うんオプションは次のとおりです。

  1. 使用する i=0はブレーク条件として-iが0に達するとループは実行されないため、i=0ループが終了した後。
for ( unsigned int i = n-1; i > 0; i-- ) {
    doStuff(i);
}
doStuff(0);
  1. ループ内で、i=0およびbreak out。ループ内でiの値を2回テストしているため、お勧めしません。また、ループ内でブレークを使用することは、一般的に悪い習慣と見なされます。
for ( unsigned int i = n-1; i >= 0; i-- ) {
    doStuff(i);
    if (i=0) break;
}
1
Tim
unsigned index;
for (unsigned i=0; i<n; i++)
{
    index = n-1 - i; // {i == 0..n-1} => {index == n-1..0}
}
1
user80452

これはループの標準ではないため、代わりにwhileループを使用します。

unsigned int i = n - 1;
while (1)
{
    /* do stuff  with i */

     if (i == 0)
    {
        break;
    }
    i--;
}
0
starblue

これはテストされていませんが、次のことを行うことができます:

for (unsigned int i, j = 0; j < n; i = (n - ++j)) {
    /* do stuff with i */
}
0
SpoonMeiser

2つの変数を使用して、1つはpをカウントし、もう1つは配列インデックスに使用します。

unsigned int Index = MAX - 1;
unsigned int Counter;
for(Counter = 0; Counter < MAX; Counter++)
{
    // Use Index
    Index--;
}
0
Steve Melnikoff