web-dev-qa-db-ja.com

forループ内のforループで同じカウンタ変数名を使用できますか?

forループ内のforループに同じカウンタ変数を使用できますか?

それとも、変数はお互いに影響しますか?次のコードでは、2番目のループにjなどの別の変数を使用する必要がありますか。それともiは問題ありませんか。

for(int i = 0; i < 10; i++)
{
  for(int i = 0; i < 10; i++)
  {
  }
}
103
Uclydde

同じ名前(識別子)を使用することができます。それは違う物になるでしょう。彼らはお互いに影響を及ぼしません。内側のループの内側では、外側のループで使用されているオブジェクトを参照する方法はありません(それを指すポインタを提供するなど、特別な規定をしない限り)。

これは一般に悪いスタイルで、混乱しがちであり、避けるべきです。

あなたが示したint iのように、オブジェクトは内側のものが別々に定義されている場合にのみ異なります。新しいオブジェクトを定義せずに同じ名前を使用すると、ループは同じオブジェクトを使用し、互いに干渉します。

136

まず、これは絶対に合法です。コードはコンパイルされて実行され、ネストされたループの本体を10×10 = 100回繰り返します。ネストされたループ内のループカウンターiは、外側のループのカウンターをhideするため、2つのカウンターは互いに独立してインクリメントされます。

外側のiは隠されているため、ネストされたループの本体内のコードは、外側のループのiではなく、ネストされたループのiの値にのみアクセスできます。ネストされたループが外部iへのアクセスを必要としない状況では、そのようなコードは完全に正当化できます。ただし、これにより読者が混乱する可能性が高いため、「保守の責任」を回避するためにこのようなコードを作成しないようにすることをお勧めします。

注:両方のループのカウンタ変数は同じ識別子iを持っていますが、2つの独立した変数のままです。つまり、not両方のループで同じ変数を使用します。両方のループで同じ変数を使用することも可能ですが、コードは読みにくいでしょう。以下に例を示します。

for (int i = 1 ; i < 100 ; i++) {
    for ( ; i % 10 != 0 ; i++) {
        printf("%02d ", i);
    }
    printf("%d\n", i);
}

これで、両方のループで同じ変数が使用されます。ただし、このコードをコンパイルせずに何をするかを理解するにはしばらく時間がかかります( demo );

55
dasblinkenlight

あなたはできる。しかし、あなたはisの範囲を知っておくべきです。外側のii_1で、内側のii_2で呼び出すと、iの有効範囲は次のようになります。

for(int i = 0; i < 10; i++)
{
     // i means i_1
     for(int i = 0; i < 10; i++)
     {
        // i means i_2
     }
     // i means i_1
}

あなたはそれらがお互いに影響を及ぼさないこと、そしてそれらの定義の範囲が異なることに気付くべきです。

25
OmG

それは完全に可能ですが、覚えておいてください、あなたは 最初に宣言されたi をアドレス指定することができないでしょう。

for(int i = 0; i < 10; i++)//I MEAN THE ONE HERE
{

  for(int i = 0; i < 10; i++)
    {

    }
}

2番目の子ループ内の2番目のループ内

for(int i = 0; i < 10; i++)
{

  for(int i = 0; i < 10; i++)//the new i
    {
        // i cant see the i thats before this new i here
    }
}

最初のiの値を調整または取得する必要がある場合は、2番目のループでjを使用してください。

for(int i = 0; i < 10; i++)
{

  for(int j = 0; j < 10; j++)
    {

    }
}

クリエイティブが十分にあれば、両方を1つのループで実行できます。

for(int i ,j= 0; i < 10; (j>9) ? (i++,j=0) : 0 ,j++)
{
    printf("%d %d\n",i,j);
}
16
Dodo

はい、内側のforループには外側のforループと同じカウンタ変数名を使用できます。

forループ から:

for ( init_clause ; cond_expression ; iteration_expression ) loop_statement
loop_statementとして使用されている式ステートメントは、init_clauseブロックスコープ、スコープとは異なるを独自に確立します。

for (int i = 0; ; ) {
    long i = 1;   // valid C, invalid C++
    // ...
}  

loop_statementの有効範囲は、init_clauseの有効範囲内でネストです。

C規格#6.8.5p5から繰り返し文[強調]

繰り返し文は、その有効範囲がその外側のブロックの有効範囲の厳密なサブセットであるブロックです。 ループ本体も、その有効範囲が反復ステートメントの有効範囲の厳密なサブセットであるブロックです _。

C規格#6.2.1p4より識別子の範囲[強調]

....内側の範囲内で、識別子は内側の範囲で宣言されたエンティティを指定します。内部スコープ内の外部スコープで宣言されたエンティティは非表示(そして表示されません)。

12
H.S.

コード/コンパイラの観点からすると、これは完全に有効で合法的なことです。内側のfor(int i = 0; i < 10; i++)ループで宣言されているint iは新しくて小さいスコープの中にあるので、宣言 は外側のループの中でint iの宣言をシャドウ します。変数iへのすべてのアクセスは、内側のスコープで宣言されたint iに行きます。外側のスコープのint iはそのまま残ります。

そうは言っても、コード品質の観点からすると、これはまったく恐ろしいことです。読みにくく、理解しにくく、誤解しやすい。しないでください。

9
CharonX

はい、あなたはそれを使うことができますが、それはかなり混乱します。最も重要なことは、ループ内のローカル変数のスコープです。変数が関数内で宣言されている限り、その変数の有効範囲はその関数です。

int a = 5;
// scope of a that has value 5
int func(){
    int a = 10;
   // scope of a that has value 10
}
// scope of a that has value 5

ループの場合と同様に、内側のループの内側で宣言された変数は異なるスコープを持ち、外側のループを宣言された変数は異なるスコープを持ちます。

for(int i = 0; i < 10; i++){
    // In first iteration, value of i is 0

    for(int i = 1; i < 10; i++){
        // In first iteration, value of i is 1
    }
    // In first iteration, value of i is 0
}

より良い方法は、内側ループと外側ループに異なる変数を使用することです。

for(int i = 0; i < 10; i++){

    for(int j = 1; j < 10; j++){

    }

}
8
Safwan Shaikh

はい、もちろん同じ名前の変数を使うことができます。

Cプログラミング変数は3つの場所で宣言できます。
ローカル変数: - 関数またはブロックを含みます。
グローバル変数: - すべての機能のうちの1つ。
仮パラメータ: - 関数パラメータ内。

しかしあなたの場合はi scopeは以下のことを気にかけなければならないでしょう

for(int i = 0; i < 10; i++)
{
     // i means 1st for loop variable
     for(int i = 0; i < 10; i++)
     {
        // but here i means 2nd for loop  variable
     }
     //interesting thing here i means 1st for loop variable
}

注:内側のループと外側のループで異なる変数を使用することをお勧めします。

8

はい。さらに興味深いことに、ブレースを開くたびに変数名を再利用できます。これは診断コードを挿入するときに便利です。開き中括弧「{」を入力し、その後に変数の宣言と使用を続けてから、中括弧を閉じると変数は消えます。これにより、中括弧の外側で宣言された変数、クラス、およびメソッドの利点を維持しながら、本文の内容に干渉しないようにすることができます。

6
SuwaneeCreek

有効範囲規則:forステートメントで宣言された変数は、そのステートメントとループ本体でのみ使用できます。

あなたのコードであなたが内部ループでiの複数のインスタンスを定義したならば、それぞれのインスタンスはそれ自身のメモリ空間を占有するでしょう。それで、結果が同じであろうととにかく心配することは何もありません。

int main(void) {

    int i = 2; //defined with file global scope outside of a function and will remain 2
    if(1)
    {       //new scope, variables created here with same name are different
        int i = 5;//will remain == 5
        for(int i = 0; i < 10; i++)
        {   //new scope for "i"

            printf("i value in first loop: %d \n", i); // Will print 0 in first iteration
            for(int i = 8; i < 15; i++) 
            {   //new scope again for "i", variable with same name is not the same
                printf("i value in nested loop: %d \n", i); // Will print 8 in first iteration
            }
        }

    }

    return 0;
}

しかし、理解が難しく、後で保守不可能なコードになるため、同じ変数名を使用することはお勧めできません。

3
Subash J

重要な部分は、内側のループパラメータがint iを含んでいるということです。 iはこのように再定義されているので、2つの変数は互いに影響しません。それらの範囲は異なります。これを示す2つの例があります。

for(int i = 0; i < 10; i++) // This code will print "Test" 100 times
{
 for(int i = 0; i < 10; i++)
 {
  puts("Test");
 }
}

上記のコードでは、内部ループパラメータにint iが含まれており、以下のコードではiのみが含まれています。

for(int i = 0; i < 10; i++) // This code will print "Test" 10 times
{
 for(i = 0; i < 10; i++)
 {
  puts("Test");
 }
}
1
Uclydde

スクリプトに問題がなくてもこれは可能ですが、その構造は避けてください。それは通常混乱を招きます

0
Bonfire