15

符号付き整数ではなく符号なし整数を使用する C++ の逆 for ループについて、Stackoverflow で調査しました。しかし、なぜ問題があるのか​​ まだわかりません(for loops を使用した Unsigned int reverse iteration を参照)。次のコードでセグメンテーション違反が発生するのはなぜですか?

#include <vector>
#include <iostream>
using namespace std;

int main(void)
{
    vector<double> x(10);

    for (unsigned int i = 9; i >= 0; i--)
    {
        cout << "i= " << i << endl;
        x[i] = 1.0;
    }

    cout << "x0= " << x[0] << endl;

    return 0;
}

問題は、オーバーフローのようなものがあるため、インデックス i がゼロになる場合であることを理解しています。しかし、符号なし整数はゼロの値を取ることが許されていると思いますね。これを符号付き整数に置き換えれば、まったく問題ありません。

符号なし整数を使用した逆ループの背後にあるメカニズムを誰かが説明してくれますか?

どうもありがとうございました!

4

5 に答える 5

31

ここでの問題は、符号なし整数が決して負にならないことです。

したがって、ループ テスト:

i >= 0

常に真になります。したがって、無限ループが発生します。

ゼロを下回ると、最大値に戻りunsignedます。 したがって、 out-of-bounds に
もアクセスx[i]します。

これは符号付き整数の問題ではありません。単純に負になり、失敗するからi >= 0です。

したがって、符号なし整数を使用する場合は、次の可能性のいずれかを試すことができます。

for (unsigned int i = 9; i-- != 0; )

for (unsigned int i = 9; i != -1; i--)

これらの 2 つは、コメントから GManNickG と AndreyT によって提案されました。


そして、ここに私のオリジナルの3つのバージョンがあります:

for (unsigned int i = 9; i != (unsigned)0 - 1; i--)

また

for (unsigned int i = 9; i != ~(unsigned)0; i--)

また

for (unsigned int i = 9; i != UINT_MAX; i--)
于 2012-01-28T08:57:18.937 に答える
6

問題は、あなたのループは i が 0 と同じくらい低くても、i が 0 より小さい場合にのみループを終了することを期待していることです。i は符号なしであるため、0 より小さくなることはありません。 . これはベクトルのサイズよりも大きいため、セグメンテーション違反が発生します。

于 2012-01-28T08:58:59.910 に答える
4

その値が何であれ、unsigned int i常に真であるi >= 0ため、forループが終了することはありません。

言い換えると、ある時点iで 0 をデクリメントしても、負でないままです。これは、おそらく 4294967295 (つまり 2 32 -1) という膨大な数が含まれているためです。

于 2012-01-28T08:58:33.983 に答える
3

問題はここにあります:

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

unsigned int の値 9 から開始し、終了定義は i >= 0 であり、これは常に true になります。(unsigned int が負になることはありません!!!)。このため、ループが最初からやり直されます (i=0 の場合、-1 が最大 uint になるため、無限ループ)。

于 2012-01-28T09:02:52.997 に答える
0

あなたが言ったように、ループの最後のステップの直後に発生するゼロ未満の符号なしの減少はオーバーフローを作成し、数値は最大値にラップアラウンドするため、無限ループになります。

符号なし整数を使用した逆ループの背後にあるメカニズムを誰かが説明してくれますか?

インデックスを使用した逆ループの私の推奨方法は次のとおりです。

for (unsigned int i = 9; i > 0; --i) {
    cout << "i= " << x[i - 1] << endl;
}

そしてそれが、通常のループの同等物に最も密接にマッピングされるためです。

for (unsigned int i = 0; i < 9; ++i) {
    cout << "i= " << x[i] << endl;
}

次に、インデックス付きの要素に複数回アクセスする必要があり、[i - 1] を連続して書き込みたくない場合は、ループの最初の行として次のようなものを追加できます。

auto& my_element = my_vector[i - 1];
于 2021-01-22T17:12:05.443 に答える