102

for1つではなく2つの変数を-loop条件でインクリメントしたいと思います。

だから次のようなもの:

for (int i = 0; i != 5; ++i and ++j) 
    do_something(i, j);

このための構文は何ですか?

4

8 に答える 8

174

一般的なイディオムは、両方のオペランドを評価し、2番目のオペランドを返すコンマ演算子を使用することです。したがって:

for(int i = 0; i != 5; ++i,++j) 
    do_something(i,j);

しかし、それは本当にコンマ演算子ですか?

これを書いた今、コメント投稿者は、それが実際にはforステートメントの特別な構文糖衣であり、コンマ演算子ではないことを示唆しました。私はGCCでそれを次のようにチェックしました:

int i=0;
int a=5;
int x=0;

for(i; i<5; x=i++,a++){
    printf("i=%d a=%d x=%d\n",i,a,x);
}

xがaの元の値を取得することを期待していたので、xに対して5,6,7..と表示されているはずです。私が得たのはこれでした

i=0 a=5 x=0
i=1 a=6 x=0
i=2 a=7 x=1
i=3 a=8 x=2
i=4 a=9 x=3

ただし、式を括弧で囲んで、パーサーに実際にコンマ演算子が表示されるようにすると、次のようになります。

int main(){
    int i=0;
    int a=5;
    int x=0;

    for(i=0; i<5; x=(i++,a++)){
        printf("i=%d a=%d x=%d\n",i,a,x);
    }
}

i=0 a=5 x=0
i=1 a=6 x=5
i=2 a=7 x=6
i=3 a=8 x=7
i=4 a=9 x=8

当初、これはコンマ演算子としてまったく動作していないことを示していると思いましたが、結局のところ、これは単に優先順位の問題です-コンマ演算子の優先順位は可能な限り低いため、式x = i ++、a++は事実上(x = i ++)、a++として解析されます

コメントありがとうございました。面白い学習体験でした。Cを長年使っています!

于 2009-08-05T09:44:20.003 に答える
57

これを試して

for(int i = 0; i != 5; ++i, ++j)
    do_something(i,j);
于 2009-08-05T09:42:21.830 に答える
6

それをしないようにしてください!

http://www.research.att.com/~bs/JSF-AV-rules.pdfから:

AV Rule 199
forループのインクリメント式は、単一のループパラメーターをループの次の値に変更する以外のアクションを実行しません。

理論的根拠:読みやすさ。

于 2009-08-05T09:53:20.483 に答える
4
for (int i = 0; i != 5; ++i, ++j) 
    do_something(i, j);
于 2009-08-05T09:42:44.060 に答える
2

私はここに来て、FORループのincrement句に2番目のインデックスをコーディングする方法を思い出しました。これは主に、C++で記述された別のプロジェクトに組み込んだサンプルでそれを観察することで実行できることがわかっていました。

今日、私はC#で作業していますが、FORステートメントはすべてのプログラミングで最も古い制御構造の1つであるため、この点でも同じルールに従うと確信しました。ありがたいことに、私は最近、古いCプログラムの1つでFORループの動作を正確に文書化するのに数日を費やしました。これらの研究には、今日のC#の問題、特に2番目のインデックス変数の動作に適用される教訓があることにすぐに気付きました。 。

不注意な方のために、以下は私の観察の要約です。[ローカル]ウィンドウで変数を注意深く観察することにより、今日起こっていることをすべて確認し、C#FORステートメントがCまたはC++FORステートメントとまったく同じように動作するという私の期待を確認しました。

  1. FORループが最初に実行されるとき、increment句(3つのうち3つ目)はスキップされます。VisualCおよびC++では、増分はループを実装するブロックの中央に3つのマシン命令として生成されるため、最初のパスでは初期化コードが1回だけ実行され、増分ブロックを飛び越えて終了テストが実行されます。これは、インデックス変数と制限変数の状態に応じて、FORループが0回以上実行される機能を実装します。
  2. ループの本体が実行される場合、その最後のステートメントは、最初の反復でスキップされた3つのインクリメント命令の最初のステートメントにジャンプします。これらの実行後、制御は自然に中間節を実装する制限テストコードに分類されます。そのテストの結果は、FORループの本体が実行されるかどうか、または制御がスコープの下部にあるジャンプを過ぎて次の命令に転送されるかどうかを決定します。
  3. 制御はFORループブロックの下部から増分ブロックに移るので、テストが実行される前にインデックス変数が増分されます。この動作は、制限句を学習した方法でコーディングする必要がある理由を説明するだけでなく、3番目の句の一部になるため、コンマ演算子を使用して追加する2次インクリメントにも影響します。したがって、最初の反復では変更されませんが、最後の反復では変更され、本体は実行されません。

ループが終了したときにいずれかのインデックス変数がスコープ内に残っている場合、それらの値は、真のインデックス変数の場合、ループを停止するしきい値より1つ高くなります。同様に、たとえば、ループに入る前に2番目の変数がゼロに初期化された場合、それがデクリメントではなくインクリメント(++)であり、ループの本体はその値を変更します。

于 2016-06-10T05:01:42.523 に答える
1

私はsquelartに同意します。2つの変数をインクリメントすると、特にそのうちの1つだけをテストする場合、バグが発生しやすくなります。

これは、これを行うための読みやすい方法です。

int j = 0;
for(int i = 0; i < 5; ++i) {
    do_something(i, j);
    ++j;
}

Forループは、ループが1つの増加/減少変数で実行される場合を対象としています。その他の変数については、ループ内で変更してください。

jに結び付ける必要がある場合はi、元の変数をそのままにして追加してみませiんか?

for(int i = 0; i < 5; ++i) {
    do_something(i,a+i);
}

ロジックがより複雑な場合(たとえば、実際に複数の変数を監視する必要がある場合)、whileループを使用します。

于 2009-08-05T10:38:25.557 に答える
0
int main(){
    int i=0;
    int a=0;
    for(i;i<5;i++,a++){
        printf("%d %d\n",a,i);
    } 
}
于 2009-08-05T09:43:01.550 に答える
0

数学を使用します。2つの演算が数学的にループの反復に依存している場合は、数学を実行してみませんか?

int i, j;//That have some meaningful values in them?
for( int counter = 0; counter < count_max; ++counter )
    do_something (counter+i, counter+j);

または、より具体的にはOPの例を参照してください。

for(int i = 0; i != 5; ++i)
    do_something(i, j+i);

特に、値で関数を渡す場合は、必要なことを正確に実行するものを取得する必要があります。

于 2015-06-11T13:17:17.670 に答える