1

現在のプロジェクトで、入れ子になった for ループが内側のループを 1 回だけ実行してから停止するという奇妙な現象に出くわしました。関連するすべての変数を注意深く調べた後でも、外側の for ループは正当な理由なく終了しました。この構造が私のプログラムに含まれる他の for ループと異なる唯一の点は、カウンター変数がパラメーターとしてループを含む関数に渡され、どこにもコピーされないことです。

そこで、問題が再現できるかどうかをテストすることにしました。

#include <stdio.h>

void someFunction(int x, int y, int width, int length)
{
    int endX = x+width;
    int endY = y+length;

    printf("x will not exceed: %i\n", endX);
    printf("y will not exceed: %i\n", endY);

    for(; x < endX; x++)
    {
        for(; y < endY; y++)
        {
            printf("(%i, %i)\n", x, y);
        }
    }
}

int main(int argc, const char *argv[])
{
    someFunction(1, 1, 5, 5);
    return 0;
}

ただし、実行すると、アプリケーションの出力は直観的な期待とは異なります。

x will not exceed: 6
y will not exceed: 6
(1, 1)
(1, 2)
(1, 3)
(1, 4)
(1, 5)

x と y が入れ替わった場合の動作は似ていますが、y 変数はインクリメントされません。この問題は、各ループのカウンターとして新しい変数を宣言するだけで解決されます。

しかし、なぜこれが起こるのですか?特定の理由で許可されていませんか?コンパイラは特定のパラメータの変更を無効にしますか?もしそうなら、なぜ一方の変数では機能するのに他方の変数では機能しないのですか?

提供されているソース コードは、特別な最適化フラグなしで GCC/G++ 4.5.3 でコンパイルされています。

4

2 に答える 2

13

y is never being reset within the x loop, so once it goes out of bounds on the first pass it stays out of bounds forevermore.

于 2012-08-08T18:24:17.813 に答える
2

xyはループ外にも存在し、ループは初期値を設定しないため、再利用しても最後の値を保持します。これは、特に、yy ループの終了後に初期値に巻き戻されない に関するものです。

この種の問題を回避するには、ループの外部の変数をインデックスとして使用しないようにします。

void someFunction(const int x, const int y, const int width, const int length)
{
    int endX = x+width;
    int endY = y+length;

    printf("x will not exceed: %i\n", endX);
    printf("y will not exceed: %i\n", endY);

    for(int ix=x; ix < endX; ++ix)
    {
        for(int iy=0; iy < endY; ++iy)
        {
            printf("(%i, %i)\n", ix, iy);
        }
    }
}

ここで、パラメーターを const にすることで、たとえ間違ってもそれらに触れないようにします。次に、ループに対してローカルな ix と iy を使用して反復を処理します。

また、何らかの理由で必要な場合を除き、接尾辞インクリメントの使用を避け、接頭辞を使用してください。整数を使用するまでは大きな変化ではありませんが、より複雑な変数を使用すると違いが生じる可能性があります。

Cプログラマーのようにコーディングすることを避けるのであれば、それも良い考えです(質問にタグを付け、C++notをタグ付けしたため)。C

慣用的な C++ の等価物は次のとおりです。

#include <iostream>

void someFunction(const int& x, const int& y, const int& width, const int& length)
{
    const int endX = x+width;
    const int endY = y+length;

    std::cout << "x will not exceed: " << endX << std::endl;
    std::cout << "y will not exceed: " << endY << std::endl;

    for(int ix=x; ix < endX; ++ix)
    {
        for(int iy=y; iy < endY; ++iy)
        {
            std::cout << '('<<ix<<", "<<iy<<')'<< std::endl;    
        }
    }
}

int main()
{
    someFunction(1, 1, 5, 5);
    return 0;
}
于 2012-08-08T18:45:32.110 に答える