|
http://www.hackerschool.org/HS_Boards/zboard.php?AllArticle=true&no=1749 [복사]
*----------------------------------------------------------------------------------------------------------*
이 카테고리는 그동안 배웠던것이라던가 공부하면서 알게된 내용들을 중심으로 혹여 참고가 될 수 있을까 싶은 내용들을
모아둔 곳입니다. 따라서 이 글들을 대상이 되는 분들은.. 프로그래밍을 갓 시작했거나 개념이 마구마구 흔들리시는 분들
정도가 되겠습니다. 그러니 너무 욕하지는 말아주세요 =_=;;;
혹시 제가 잘못 알고 있는 부분들이라던가 궁금한 것이 있으면 쪽지 남겨주시거나 리플을 달아주시면 감사하겠습니다.
*----------------------------------------------------------------------------------------------------------*
이번 스터디에서는 반복문을 짚고 넘어가려고 합니다.
사실 프로그램을 배우는 사람 치고 반복문의 유용함이나 중요성을 모르는 사람이 있겠습니까만, 그 기능을 제대로 활용한다는 게 그리 쉬운 건 아닌 것 같습니다.
반복문이 필요한 곳을 찾는다거나 반복 조건을 찾아내는 것 까지는 여러분의 손에 맡기고, 제가 관심을 가지려 하는 것은 반복문을 사용할때 어떻게 하면 좀 더 효율적으로, 강력하게 쓸 수 있을까 하는 것 입니다.
우선 반복문의 구조부터 알아보죠.
반복문에는 단순 반복을 위한 while문과 우선실행후 반복을 위한 do/while문 그리고 while문의 업그레이드버전(?)인 for문이 있지요. 이러한 세 종류의 반복문 모두 공통적으로 가지고 있는 특징들이 있습니다.
1. 반복이 되는 구간
2. 반복 조건
3. 변화 요소 (또는 인덱스)
4. 탈출/Skip 조건
5. 실행요소 (또는 목적)
모든 반복문에는 당연히 반복되는 구간이 필요합니다. 구간 지정도 없이 아무데서나 들쑥날쑥하게 반복이 된다면 반복문으로서의 의미가 없어지지요. 그래서 반드시 반복이 필요한 요소는 지정 된 구간 안에서만 정의되어야 합니다.
그리고, 어떠한 루틴이든 시작이 있으면 반드시 끝이 있기 마련이지요. 반복문도 마찬가지 입니다. 그 어떠한 반복문도 반드시 반복 조건을 필요로 합니다. 그래서 이 조건들을 기준으로 반복할 것인지, 아니면 해당 구간을 탈출 할 것인지를 결정하게 됩니다. 무한 반복은 바로 '반복 조건이 항상 true다' 라는 의미에 지나지 않습니다.
다음으로, 반복 조건이 필요하다고 하는 것은 그 내부에서 무언가 변화가 일어나고 있다는 것을 의미합니다. 그 어떤 변화도 없는 반복은 곧 무한 반복을 의미하죠. 따라서 시작이 있고 끝이 있는 반복을 만들기 위해서는 어딘가에는 반드시 변화되는 요소가 존재해야 합니다. 우리가 가장 많이 사용하는 i(흔히 인덱스 변수라고 하죠)가 바로 여기서 말하는 변화 요소, 인덱스에 해당합니다. 이 인덱스 변수가 증가 또는 감소 함으로서 반복 조건이 위배 되는지 아닌지를 판단하게 되는것이죠.
여기서 잊지 말아야하는 중요한 사실 한가지!
반복 조건과 변화 요소는 반드시 짝을 이루어야 합니다.
만약 반복 조건은 ( i<100 ) 인데 k 만 죽어라 증가하고 있다면 전혀 의미가 없지요.
또는 반복 조건은 4가지를 요구하는데 3가지 요소만 변화하고 있다면 이 역시 의미없는 조건이 될 뿐입니다.
탈출/Skip 조건이라는 것은 필요할때도 있고 필요에 따라서 사용하게 되며, 이때 사용하는 키워드가 바로 break와 continue입니다.
if 또는 switch등 분기문과 함께 사용되며, 사용하기에 따라서 코드를 매우 간결하게 만들 수 있습니다. break는 큰 무리 없이 사용할 수 있으나, continue는 주의해야 할 점들이 몇가지 존재하기에 차후에 따로 설명하도록 하겠습니다.
마지막으로 실행요소가 존재합니다. 이 실행요소라는 것은 사실상 반복문이 존재해야하는 이유이겠지요. 아무런 이유도 없이 반복문을 돌리기만 한다면 무슨 소용이 있겠습니까? 물론, 아무것도 없이 돌리는 반복문도 분명히 존재합니다.
------------------------
for( i=0; i<10000000; i++ ) ;
------------------------
이런거 말이죠. 이런 경우는 왜 반복문을 만들어야 했을까요? 대부분 이러한 경우도 나름대로의 목적을 가지고 있습니다.
바로 딜레이이지요. 1~10000000 루프를 반복하는 동안에는 아무런 입력도, 동작도 하지 않기 때문에 시간이 지연되는 효과를 보이게 되지요.(물론 요즘은 타이머를 쓰기 때문에 굳이 이런 식으로 안합니다) 때문에 딜레이 효과를 위해서 사용을 하긴 합니다.
하지만 이것도 목적을 가진 코드이므로 실행문이 없다 할지라도 없는 것 자체가 실행 요소라 할수 있다는 것입니다.
반복문의 기본은 뭐니뭐니해도 while문입니다.
대부분의 책을 보면 while문은 아래와 같은 구조를 갖는다고 설명이 되어있지요.
while( 반복조건 )
{
실행문;
}
있을건 다 있다고... 생각 할 수 있습니다만, 제 스터디의 흐름과 구색을 맞추기 위해 몇가지를 추가해 보도록 하겠습니다.
반복 조건은 있으나 그 반복조건을 만족시키기위한 요소, 즉, 인덱스가 보이질 않죠? 사실 보이지 않아도 문제 될 것은 없습니다만, 좀 더 깊이 이해하기 위해 아래와 같이 구조를 바꾸어 보도록 하겠습니다.
while( 반복조건 )
{
실행문;
인덱스;
}
위의 인덱스는 실행문의 앞에 올 수도 있고 뒤에 올 수도 있습니다.
반복문을 필요로하는 성격에 따라서 그 위치는 조절을 해야하겠지만, 보통은 실행에 앞서 어떠한 변화가 일어나는 것은 그다지 바람직하지 않다고 보이므로 가급적 실행문 뒤에 위치 시키는 것이 좋다고 생각됩니다.
이제 반복/탈출 조건에 대해 생각해 봅시다.
while문에서는 반복 구간에 들어가기 전에 반복조건을 검사합니다. 만약 조건을 만족한다면 내부 루프로 진입을 하게 되겠지요. 그리고 실행문을 실행 한 후 인덱스를 변화 시키게 되고 다시 처음로 돌아가 반복조건을 검사하게되고, 루프 진입을 결정하게 될겁니다.
이해를 돕기 위해 아래와 같은 구조로 while문을 구성했다고 생각해 봅시다.
while( true ) // 그냥 1을 넣기도 합니다. (true는 '0 이 아닌 다른 수'로 정의되기 때문이죠)
{
실행문;
인덱스;
}
이 코드는 전형적인 무한 루프의 구조입니다. 여기에 탈출 조건을 사용하면 ()안의 반복 조건을 사용했을때와는 달리 프로그래머가 원하는 시점에서의 루프 탈출을 정의 할 수 있습니다. 무엇보다 다음 두가지 코드를 비교 해 볼까요?
while( true ) while( true )
{ {
if( 탈출조건 ) 실행문;
break; 인덱스;
실행문; if( 탈출조건 )
인덱스; break;
} }
두 코드는 if문이 배치 된 것이 반복 구간의 앞이냐 뒤냐 하는 것이 다르죠. 두 실행문에는 과연 어떠한 차이가 있을까요?
아래 코드를 실행시켜보면 어떠한 차이가 생길까요?
i=0; i=0;
while( true ) while( true )
{ {
if( i>10 ) printf( "%d\n", i );
break; i++;
printf( "%d\n", i); if( i>10 )
i++; break;
} }
왼쪽 식에서 i는 0인 상태로 루프에 진입합니다. i는 10보다 작으므로 0을 출력하고 i가 증가 되겠지요. 다시 처음으로 돌아가서 비교를 하고 다시 출력.. 10이 출력 될때까지 동일하게 작동을 합니다. 마지막으로 i가 10->11 이 되면 비교 조건에 의해 break;를 만나게 되어 루프를 탈출합니다. 따라서 0~10까지 출력이 되는 루프가 되겠습니다.
그러면 오른쪽 식은? 오른쪽에서도 i=0인상태로 루프에 진입합니다. 그리고 먼저 0을 출력한 후 비교를 하고 루프 처음으로 돌아갑니다. 마찬가지로 10이 출력 될때까지 동일하게 반복합니다. 마지막으로 i가 10->11이 되면 비교 조건에 의해 루프를 탈출합니다.
그러므로 0~10까지 출력이 되는 루프가 됩니다.
아니 그러면 도대체 무슨 차이가 있다는거죠?..라고 말씀 하시겠죠? 그러나 여기에는 어마어마한 차이가 있습니다.
확인 해 보도록 하죠.
만약 탈출조건이 i>10이 아니라 i<5 || i>10 이라고 했을때는 어떻게 될까요?
먼저 왼쪽 식부터 보겠습니다.
i=0으로 루프로 진입합니다. 그리고 if문을 만나며 탈출 조건을 확인하겠지요. 이때 i=0 이므로 i<5에 해당하여 break;가 수행됩니다. 즉, 루프를 탈출하게 되지요. 이말은 곧, 루프에서 아무것도 하지 않은 채 탈출을 하게 된다는 의미가 됩니다. 물론, i++;도 거치지 않기 때문에 i도 0인 상태 그대로 탈출하게 됩니다.
자 그러면 오른쪽 식에서는 어떤 일이 벌어질까요?
i=0인 상태로 루프에 진입하여 i 즉, 0을 출력합니다. 그리고 i++를 만나서 i가 증가되겠지요. 그리고는 탈출 조건을 만나 루프를 탈출하게 됩니다. 왼쪽 식과는 달리 화면에는 0을 출력 할것이고, i 또한 0이 아닌 1이 되겠지요.
한가지 더!
위 식에서 탈출 조건이 i<1 || i>10 이라면 어떻게 될까요?
왼쪽 식은 위의 결과와 다르지 않겠지만, 오른쪽 식은 i<1의 영향을 받지 않고 0부터 10까지 출력하고 종료가 될 것입니다.
이게 어떻게 된 일일까요? 동일한 탈출 조건에서도 if문이 위에 위치했을때는 실행문을 전혀 실행하지 않던 것이 아래에 내려가면 한번, 또는 전부 실행하고 종료가 됩니다. 이것이 바로 break 위치에 따른 미묘한 차이이기도 하죠.
그런데, 오른쪽 식의 결과, 어디선가 많이 본 것 같지 않으신가요?
네, 그렇습니다. 바로 do/while문의 결과와 똑같습니다.
위의 두 식을 바꾸면 이렇게 됩니다.
i=0; i=0;
while( i>=1 && i<=10 ) do
{ {
printf( "%d\n", i ); printf( "%d\n", i );
i++; i++;
}; }while( i>=1 && i<=10 );
(※ while()의 괄호 안에 들어가는 반복 조건은 루프 중간의 if가 가지고 있던 탈출 조건의 역 이라는것에 주의 하십시오.
따라서, 반복 조건에는 (i<1 || i>10 )의 역인 ( i>=1 && i<=10 )이 들어가야 합니다.)
while문과 do/while문의 결정적인 차이는 사실 탈출/반복 조건을 "루프의 어느 시점에서 검사하느냐" 라는 것입니다.
즉, while문과 탈출 조건의 위치 관계만 분명히 파악할 수 있다면 거의 대부분의 루프는 whlie문 만으로도 해결 할 수 있습니다.
그럼 다음 스터디 때 뵙겠습니다.
출저=때릴꺼야 |
Hit : 9031 Date : 2011/05/01 11:37
|