C++等で、for 文を unsigned int のカウンタで N から 0 までループをするときに


for( unsigned int i=10; i>=0; i-- )

と書くと、i=0 の次は正の最大値になってループが終わりません。

皆さんはこういう場合(たとえばvectorを逆順にアクセスし、インデクスの値もループ内で使いたい場合)どうしますか?
非常に主観的かつ興味本位ですが、int を使う以上に「気持ちいい」解決策があれば見てみたいと思い質問しました。

回答の条件
  • 1人2回まで
  • 登録:2008/02/20 12:17:09
  • 終了:2008/02/20 18:25:27

回答(9件)

id:HowAreYou No.1

HowAreYou回答回数91ベストアンサー獲得回数172008/02/20 12:29:13

ポイント30pt

i が最大値を取らないのなら

for ( unsigned int i = 10; i <= 10; i-- )

とか。

id:yamaryoxxxx

ありがとうございます。

しかし可読性が微妙で、こう書くくらいなら int を使うだろうなと思います。

2008/02/20 12:35:22
id:JULY No.2

JULY回答回数966ベストアンサー獲得回数2472008/02/20 12:43:14

ポイント30pt

unsigned int i = UINT_MAX;

do {

    ほにゃらら;

    i--;

} while (i != UINT_MAX);

とすれば、UINT_MAX 回、ほにゃららが実行されることにはなるかな。

でも、コメントなしで、この終了条件が理解されることは無いと思う。

id:yamaryoxxxx

ありがとうございます。

ループの外側に変数を作れば

unsigned int i=N;

do{

xxx;

i--;

}while( i != 0 )

とできますね。

2008/02/20 13:42:50
id:freemann No.3

freemann回答回数309ベストアンサー獲得回数502008/02/20 13:16:09

ポイント30pt

iの値を1増やして

for(unsigned int i = 11;i>0;i--) printf("%d",i-1);

という感じに、iが使われるところで-1する。

または、

for(unsigned int i = 10,int j = 10;j >= 0;i--,j--)

という具合に、ループのカウンタだけに使用するintの変数を追加する。

id:yamaryoxxxx

ありがとうございます。

前者はバグの原因になりそうですね。

後者のような書き方ができるのですね。

でもやっぱり可読性が悪くなるのは避けられないみたいですね。

2008/02/20 13:46:07
id:Bookmarker No.4

しおり回答回数191ベストアンサー獲得回数342008/02/20 13:37:00

ポイント30pt

ループカウンターとインデックスを分けるとか。

#include <vector>
#include <iostream>

typedef std::vector<int> vector_int;

int main()
{
    vector_int ary;
    ary.push_back(1);
    ary.push_back(2);
    ary.push_back(3);
    for ( vector_int::size_type n = ary.size(); n > 0; --n ) {
        vector_int::size_type i = n - 1;
        std::cout << ary[i] << "\n";
    }
}
id:yamaryoxxxx

ありがとうございます。

色々なやり方を紹介していただきましたが、ところで

皆様は実際にこういう場面でこの書き方をされるのでしょうか?

それともやはり int で書きますか?

2008/02/20 13:48:59
id:wasisan No.5

wasisan回答回数86ベストアンサー獲得回数72008/02/20 13:57:29

ポイント40pt

質問とはあまり関係ないですが,

これはいわゆる「番兵」の問題に似ていますね.

番兵 - Wikipedia

方法としては2番の回答と同じことです.

unsignedの場合は,最大値(UINT_MAX)がNULL(無効なデータ)なのだと考えれば

わりと綺麗に理解できるかもしれません.

 #define UINT_NULL UINT_MAX
 
 for ( unsigned int i = 10; i != UINT_NULL ; i-- ) {
 ...
 }

実際,STLなどではイテレータでこういう書き方(!=を使いNULLと比較する)

をよくします.

id:yamaryoxxxx

これは気持ちがいい(主観ですが)ですね!

#define するだけで全く可読性が変わりますね。

ありがとうございます。

2008/02/20 14:02:35
id:b-wind No.6

b-wind回答回数3344ベストアンサー獲得回数4402008/02/20 14:00:28

ポイント30pt
for( unsigned int i=0; i<=10; i++ ) {
  unsigned int index = 10 - i;
  // do somthing
}

として実際のインデックスには index を使うとか?

id:yamaryoxxxx

ありがとうございます。

これはやったことがありますが、何となく負けかなと思っています。

2008/02/20 14:06:50
id:i_kumagoro No.7

i_kumagoro回答回数170ベストアンサー獲得回数582008/02/20 16:56:22

ポイント30pt

制約がないなら別変数を用意します。

この条件で無理矢理するなら

for ( unsigned int i = 10; i+1 >= 1; i-- ) {
...
}

でしょうか。一応 unsigned じゃなくなってもそのまま動きます。

書いた人以外が見たらなんだこりゃと思われそうですが。

id:yamaryoxxxx

なるほど、 i>=0 はダメだけど i+1>=1 は ok なんですね。

勉強になります。ありがとうございます。

2008/02/20 17:40:45
id:Bookmarker No.8

しおり回答回数191ベストアンサー獲得回数342008/02/20 17:31:09

ポイント50pt

ところで皆様は実際にこういう場面でこの書き方をされるのでしょうか?

それともやはり int で書きますか?

使い捨てのプログラムの場合は符号あり整数を使う場合もありますが、基本的には回答 4 で書いたように符号なし整数を使います。(その場合、別の変数に代入せず、使う場所で -1 する場合もあります。)

というか、std::size_t や foo::size_type など実際の型を隠蔽した型(名前)を使うので、符号あり/なしどちらでも良いように書きます。


なお、C/C++ で整数演算時のオーバーフロー/アンダーフローの動作は未定義だという認識なので、回答 2回答 5 のように 0 - 1 が最大値になることを期待する書き方はしません。

id:yamaryoxxxx

なるほど、確かにアンダーフローを前提に書くのは危ない面がありますね。

回答 4 や回答 6 のきれいさが理解できました。ありがとうございます。

2008/02/20 17:50:59
id:AZUY No.9

AZUY回答回数343ベストアンサー獲得回数122008/02/20 18:07:49

ポイント30pt

こんばんは。


そもそも、vector::size_typeの最大値が、

unsigned int の最大値をこえないという保障はあるのでしょうか?

保証がないのなら、この時点で負けてると思います。

id:yamaryoxxxx

ありがとうございます。その通りでした。

回答 8 にあるように、そもそも隠蔽した型で符号あり/なしによらないコードを書くべきで、

そうではなく直接 unsigned int を使う場合に限り上の色々な方法を使えばよい、というように

理解しました。

稚拙な質問ですみません。勉強になりました。

皆様、ありがとうございます。

2008/02/20 18:23:22
  • id:i_kumagoro
    C言語ではunsigned intでの演算結果は常に定義されています。
    C99標準では以下のように書かれています。

    The keyword unsigned is something of a misnomer, suggesting as it does in arithmetic that it is non-negative but capable of overflow. The semantics of the C type unsigned is that of modulus, or wrap-around, arithmetic for which overflow has no meaning. The result of an unsigned arithmetic operation is thus always defined, whereas the result of a signed operation may be undefined.

    0 - 1 が最大の正数になったり、そこに 1 足して 0 になるのを期待するコードが危険であることを否定するものではありませんが。
  • id:yamaryoxxxx
    やまりょう 2008/02/20 18:40:31
    unsigned int を直接使う場合は UINT_MAX で判定して問題ないのですね。
    どうもありがとうございます。
  • id:Sampo
    for (unsigned int i = N + 1; i-- > 0; ) {
    // N >= i >= 0
    }

    をよく使います。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません