'for'루프 내부의 'for'루프가 동일한 카운터 변수 이름을 사용할 수 있습니까?


107

for루프 내부의 루프에 동일한 카운터 변수를 사용할 수 있습니까 for?

아니면 변수가 서로 영향을 미칠까요? 다음 코드는, 제 2 루프에 다른 변수를 사용한다 j이거나, 또는 i미세?

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

72
혼란 스럽습니다. 코드 리뷰에서 저를 지나치지 않을 것입니다. 그러나 그것은 합법적입니다. i범위가 다른 두 개의 다른 변수가 있습니다 . -WshadowGCC와 함께 사용 하면 이러한 문제가 자동으로보고됩니다.
Jonathan Leffler

15
-Wshadow포함되지 않은 것이 놀랍습니다 -Wall.
leftaroundabout

5
@leftaroundabout -Wshadow은 전역 변수의 섀도 잉에 대해서도 경고하며, 이는 대규모 프로젝트에서 쉽게 성가 시게 할 수 있습니다.
Cubic

9
@leftaroundabout 더욱 놀랍게도, 심지어는 -Wextra포함되지 않습니다 -Wshadow. 나는 이것이 일부 프로젝트에서 충분히 일반적이거나 일부 gcc 개발자가 코딩 스타일로 섀도 잉을 좋아하여 이와 같이 제외되는 것을 보증합니다.
hyde

5
@leftaroundabout Cubic이 말한 것을 반향하는 -Wshadow것은 끔찍한 오 탐률을 가지고있어 완전히 쓸모 없게 만듭니다. 범위는 이유가 있으며 섀도 잉은 문제가되지 않는 선험적 입니다. 이제 -Wshadow-local(참고 : not -Wshadow=local )은 매우 다릅니다. 그러나 안타깝게도 GCC는 지금까지 트렁크에 포함하는 것을 거부했습니다 (이를 포함하는 GCC의 포크가있는 것으로 보이지만).
Konrad Rudolph

답변:


140

동일한 이름 (식별자)을 사용할 수 있습니다. 다른 개체가됩니다. 서로 영향을주지 않습니다. 내부 루프 내부에는 외부 루프에 사용 된 객체를 참조 할 수있는 방법이 없습니다 (포인터를 제공하는 것과 같이 특별히 준비하지 않는 한).

이것은 일반적으로 나쁜 스타일이며 혼동을 일으키기 쉬우므로 피해야합니다.

개체는 int i표시된 것처럼 내부 개체가 별도로 정의 된 경우에만 다릅니다 . 새 객체를 정의하지 않고 동일한 이름을 사용하면 루프가 동일한 객체를 사용하고 서로 간섭합니다.


3
for (i) 및 for (j) 중첩 및 i ++ 내부를 사용하면 외부 루프 변수가 증가합니다. 그러나 두 루프에서 동일한 식별자를 사용하면 범위가 다른 변수이기 때문에 당신이 말하는 것은 정확합니다.
KYL3R

3
@BloodGain : "Object"는 C 표준에서 사용되는 기술 용어입니다. 여기서 일부러 사용했습니다.
Eric Postpischil

1
@EricPostpischil : 아, 그렇군요. 나는 표준에서 그 정의를 알지 못했고, C는 우리가 일반적으로 사용하는 용어를 사용한다는 의미에서 "객체"를 가지고 있지 않기 때문에 새로운 프로그래머들에게 오해 할까 두려웠다. 나는 C11 표준에서 그것을 보았고 이제 C11 이전에 그렇게 정의되었는지 궁금합니다.
Bloodgain

1
그랬다. C99 표준에서는 3.15가 아닌 3.14입니다. 그러니 내 변명은 없습니다. 질문하는 방법을 알려줄 것입니다. <:-|
Bloodgain

1
더 일반적으로 : 중첩 된 범위에서 변수 이름을 재사용하는 것을 막을 수있는 방법은 없습니다. 물론 혼란스러운 코드를 작성하는 것에 대한 하나님의 처벌에 대한 두려움을 제외하고.
Isaac Rabinovitch

56

첫째, 이것은 절대적으로 합법적입니다. 코드가 컴파일되고 실행되어 중첩 된 루프의 본문을 10x10 = 100 번 반복합니다. i중첩 루프 내부의 루프 카운터 는 외부 루프의 카운터를 숨기 므로 두 카운터가 서로 독립적으로 증가합니다.

외부 i가 숨겨져 있기 때문에 중첩 된 루프 본문 내부의 코드 는 외부 루프가 i아닌 중첩 된 루프 의 값에만 액세스 할 수 있습니다 i. 중첩 루프가 외부에 액세스 할 필요가없는 상황에서 i이러한 코드는 완벽하게 정당화 될 수 있습니다. 그러나 이는 독자들에게 더 많은 혼란을 야기 할 수 있으므로 "유지 관리 책임"을 피하기 위해 그러한 코드를 작성하지 않는 것이 좋습니다.

참고 : 두 루프의 카운터 변수가 동일한 식별자를 가지더라도 i두 개의 독립 변수로 남아 있습니다. 즉, 두 루프에서 동일한 변수를 사용 하지 않습니다 . 두 루프에서 동일한 변수를 사용하는 것도 가능하지만 코드를 읽기가 어렵습니다. 다음은 예입니다.

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

이제 두 루프 모두 동일한 변수를 사용합니다. 그러나 컴파일하지 않고이 코드가 수행하는 작업을 파악하려면 시간이 걸립니다 ( demo ).


4
질문이 "동일한 카운터 변수 사용"으로 표현되어 있으므로 재정의가 발생할 때만 섀도 잉이 발생한다는 점도 지적하고 싶습니다. int내부 for 루프에서를 생략하면 , 즉 실제로 동일한 카운터 변수를 사용하면 내부 루프가을 떠나기 때문에 외부 루프가 한 번만 실행됩니다 i == 10. 이것은 사소한,하지만이 설명이 문제는 언급 된 방법 주어진 제공합니다 생각
이스턴 Bornemeier을

@EastonBornemeier 당신이 맞습니다, 나는 대답 본문에서 "동일한 변수"의 문제를 해결해야한다고 생각했습니다. 감사합니다!
dasblinkenlight

@EricPostpischil "Variable shadowing"은 공식 용어로, wikipedia에 자체 페이지가 있습니다. 그래도 표준 문구와 일치하도록 답변을 업데이트했습니다. 감사합니다!
dasblinkenlight

2
@dasblinkenlight : 사실 방향에 대해 뇌 경련이 있었고 내부 이름이 외부 이름을 가리고 있습니다. 내 이전 의견은 그 점에서 잘못되었습니다. 죄송합니다. (그러나 이것은 공식적인 의미가 아니라 영어의 의미입니다. 위키피디아는 C 또는 일반적으로 프로그래밍에 대한 공식 간행물이 아니며 용어를 정의하는 사무실이나 권위있는 기관을 알지 못합니다.) C 표준은 사용합니다. "숨기기"가 바람직합니다.
Eric Postpischil

특히 "동일한 변수"예제에서 좋습니다. 그러나 " 코드가 예상대로 컴파일되고 실행될 것입니다"가 "코드를 주의 깊게 읽고 예상되는 모든 결과를 이해하는 사람 으로 컴파일되고 실행될 것입니다. "라고 생각합니다. 독자들에게 더 많은 혼란을 야기 할 가능성이 있으며, 문제는 독자들이하는 것 이외의 다른 것을 기대할 수 있다는 혼란스러운 독자 입니다.
TripeHound

26

할 수 있습니다. 그러나 is 의 범위를 알고 있어야합니다 . 외부 iwith i_1및 내부 iwith를 호출하면 s i_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
}

서로 영향을주지 않으며 정의 범위 만 다릅니다.


17

그것은 완전히 가능하지만 첫 번째 선언 된 i 를 해결할 수 없다는 것을 명심하십시오.

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

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

    }
}

두 번째 자식 루프 내의 두 번째 루프

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의 값을 조정하거나 얻으려면 두 번째 루프에서 j를 사용하십시오.

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

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

    }
}

창의력이 충분하다면 한 번의 루프에서 두 가지를 모두 수행 할 수 있습니다.

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

6
코드 검토 중에 중첩 된 루프에서 음영 처리 된 i 변수를 발견하면 코칭 기회로 간주됩니다. 마지막 예제와 같이 내부 루프를 난독 화하는 누군가를 잡았다면 (즉, 하나의 루프가 아님) 창 밖으로 던져 버릴 수 있습니다.
Bloodgain

그것은 하나가 하나 개의 루프 에 대한 이 2 인 경우는과 키워드하면서 키워드에 대한 두 개의 키워드 동안이나있을 것입니다, 루프
도도

3
그래서 루프 를 난독 처리 했다고 말한 것 입니다. 당신은 여전히 ​​루핑 중이며 덜 ​​분명한 구문으로 숨겼습니다. 그리고 그것은 모든면에서 더 나쁩니다.
Bloodgain

12

예, 내부 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 Standards # 6.8.5p5 반복문에서 [강조]

반복 문은 범위가 둘러싸는 블록 범위의 엄격한 하위 집합 인 블록입니다. 루프 본문은 범위가 반복 문의 범위의 엄격한 하위 집합 인 블록이기도합니다 .

C Standards # 6.2.1p4 식별자 범위 [강조]

.... 내부 범위 내에서 식별자는 내부 범위에 선언 된 엔티티를 지정합니다. 외 범위에서 선언 엔티티 숨겨진 내부 범위 (및 보이지 않음).


10

코드 / 컴파일러 관점에서 이것은 완벽하게 타당하고 합법적 인 일입니다. int i내에서 선언 된 for(int i = 0; i < 10; i++)루프, 새롭고 더 작은 범위에 있다고 선언 그래서 그림자 의 선언 int i다른 단어와 외부 루프에서 (또는, 상기 변수의 상기 내부 영역 내의 모든 액세스 i받는 이동 int i내측 범위에서 선언 int i외부 범위에 그대로 둡니다 ).

즉, 코드 품질 관점에서 이것은 완전히 끔찍합니다. 읽기 어렵고 이해하기 어렵고 오해하기 쉽습니다. 하지마.


8

예, 사용할 수는 있지만 꽤 혼란 스럽습니다. 가장 중요한 것은 루프 내부의 지역 변수 범위입니다. 변수가 함수 내에서 선언 된 경우 해당 변수의 범위는 해당 함수입니다.

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

예, 확실히 같은 이름 변수를 사용할 수 있습니다.

C 프로그래밍 변수는 다음 세 위치에서 선언 할 수 있습니다.
로컬 변수 :-함수 또는 블록 내부.
전역 변수 :-모든 기능 중.
형식 매개 변수 :-기능 매개 변수에서.

그러나 귀하의 경우 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
}

참고 : 내부 및 외부 루프에 서로 다른 변수를 사용하는 것이 가장 좋습니다.


6

예-더 흥미롭게도 중괄호 세트를 열 때마다 변수 이름을 재사용 할 수 있습니다. 이것은 종종 진단 코드를 삽입 할 때 편리합니다. 여는 중괄호 '{'다음에 변수 선언 및 사용을 입력 한 다음 중괄호를 닫으면 변수가 사라집니다. 이렇게하면 중괄호 외부에 선언 된 변수, 클래스 및 메서드의 이점을 계속 유지하면서 본문의 어떤 것도 방해하지 않을 것입니다.


3

범위 규칙 : 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;
}

하지만 이해하기 어렵고 나중에 유지 관리 할 수없는 코드가되므로 동일한 변수 이름을 사용하지 않는 것이 좋습니다.


1

중요한 부분은 내부 루프 매개 변수에 int i. i이 방식으로 재정의 되기 때문에 두 변수는 서로 영향을주지 않습니다. 범위가 다릅니다. 이를 보여주는 두 가지 예는 다음과 같습니다.

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");
 }
}

0

글쎄, 당신은 당신의 스크립트에 문제없이 이것을 할 수있다. 그러나 당신은 그 구조를 피해야한다. 일반적으로 혼란을 야기합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.