본문 바로가기

C언어 강좌

[C언어_08] 중첩 반복문/무한루프: 문제풀이에 어떻게 응용하는가

 

 

 

안녕하세요, 이번 시간에는 앞서 배웠던 반복문을 조금 더 심화적으로 살펴볼 것입니다.

또한 중첩 반복문이나 무한 루프는 개념적인 부분보다는 어떻게 응용하는가가 중요하기 때문에

어떠한 논리로 접근해야 하는지 알려드리겠습니다.

 

 


| 중첩 반복문(Nested Loop)

중첩 반복문이란, 말 그대로 반복문이 중첩되어있는 구조, 즉 반복문 속에 반복문이 존재하는 구조를 말합니다.

앞선 강좌에서 배웠던 기본적인 반복문을 잘 이해했다면, 이 파트를 이해하는 것도 어렵지 않을 것입니다.

 

우선 가장 기본적인 중첩반복문 사용 예제를 보여드리겠습니다.

 

int i, j;
int n = 5;
for(i = 0; i < n; i++){
    for(j = 0; j < n; j++){
        printf("*");
    }
    printf("\n");
}

위 코드를 실행하면 콘솔창에는 무엇이 출력될까요?

 

먼저 바깥쪽 반복문을 보시면, 우리가 선언한 변수n이 5이므로 총 5사이클을 돌게 됩니다.

그리고 그 큰 사이클이 한바퀴 돌 때, 안쪽 반복문도 5사이클을 돌게 됩니다.

그렇게 총 5x5사이클을 돌고 반복문을 탈출하는 것이죠.

 

이렇게 구조적으로 코드를 이해했을 때,

위 코드의 실행 결과는 '*'로 이루어진 정사각형임을 알 수 있습니다.

 

실행결과
*****
*****
*****
*****
*****

 

| 중첩 반복문의 분류(독립적, 종속적)

 

중첩 반복문을 두 가지 분류로 나눈다면,

    

    바깥쪽 반복문과 안쪽 반복문이 독립적으로 사이클을 수행하는 독립적 중첩반복문,

    바깥쪽 반복문과 안쪽 반복문이 서로 영향을 받아 종속적인 형태를 띠는 종속적 중첩반복문

 

으로 나눌 수 있습니다.

 

방금전에 다루었던 코드의 경우는 i, j변수간에 영향을 주고받는 요소가 없으므로 독립적인 중첩반복문이라고 할 수 있겠습니다. 그렇다면 종속적인 중첩반복문의 예제를 함께 살펴보겠습니다.

 

int i, j;
int n = 5
for(i = 1; i <= n; i++){
    for(j = 1; j <= i; j++){
        printf("*");
    }
    printf("\n");
}

위 코드를 보시면 초록색으로 표시해놓은 부분에서 바깥쪽 반복문의 변수인 i가 안쪽 반복문의 변수인 j에 영향을 미치고 있는 것으로 보아 종속적 중첩반복문입니다.

 

아까처럼 구조적으로 분석해봅시다.

바깥쪽 반복문은 n=5이므로 5회 사이클을 돌게 되는데, 이때 각 사이클마다 안쪽 반복문의 실행 양상이 어떤 식으로 변화하는지를 알 수 있어야 합니다.

 

Loop1:

    i=1이므로 안쪽 반복문은 1cycle

    -> print *\n

Loop2:

    i=2이므로 안쪽 반복문은 2cycle

    -> print **\n

Loop3:

    i=3이므로 안쪽 반복문은 3cycle

    -> print ***\n

Loop4:

    i=4이므로 안쪽 반복문은 4cycle

    -> print ****\n

Loop5:

    i=5이므로 안쪽 반복문은 5cycle

    -> print *****\n

 

실행결과
*
**
***
****
*****

위와 같은 과정에 의해서 출력된 결과물은 보시는 바와 같이 삼각형 모양임을 알 수 있습니다.

 

이번엔 삼각형을 뒤집어 출력해 볼까요? 뒤집어진 삼각형 모양을 만드는 구조를 생각해보세요.

이전 것과 같이 큰 사이클은 5번 돌아가겠지만, 큰 사이클이 매 회 돌아갈 때마다 작은 사이클이 돌아가는 횟수가 적어지도록 설계면 됩니다.

 

Loop1(i=1): 5회 반복  *****

Loop2(i=2): 4회 반복  ****

Loop3(i=3): 3회 반복  ***

Loop4(i=4): 2회 반복  **

Loop5(i=5): 1회 반복  *

 

바깥쪽 반복문이 돌아가며 i가 1부터 5까지 증가하는 상황에서 과연 안쪽 반복문의 조건은 어떻게 걸어주어야 할까요?

한번 눈을 감고 생각해 보시길 바랍니다. 구조가 머리속에 떠오르신다면 중첩 반복문을 응용하는 능력이 생긴 것입니다!정답이 궁금하시다면 댓글로 요청해주세요. 비밀댓글로 알려드리겠습니다.

 

| 무한 루프의 활용

다음으로 살펴볼 내용은 무한 루프입니다. 무한 루프는 말 그대로 실행 흐름이 반복문 내에서 빠져나오지 못하고 지속되는 상태를 의미합니다. 하지만 소제목에서 기술했듯이 우리는 이러한 현상을 '활용'할 것입니다.

그러므로 이것의 목적은 영원히 프로그램을 끝나지 않게 하려는 것이 아니라

"내가 원하는 조건을 충족할 때 까지 반복시키는" 것이 목적입니다.

 

가령 정수 -1을 입력받을 때까지 계속 숫자를 입력받는 루프라던가,

파일이나 문자열의 끝에 도달할 때까지 반복되도록 하는 루프를 예로 들 수 있을 것입니다.

 

이제부터 제시할 예제는 -1이 입력되기 이전에 입력받은 모든 숫자들의 총합과 평균을 출력하는 예제입니다.

(-1미포함)

 

int sum = 0;
int numCount = 0;
float avg;

while(1){
    int num;
    scanf("%d", &num);
    if( num == -1 ) break;
    
    sum += num;
    numCount++;
}
avg = (float)sum / numCount;
printf("total: %d\navg: %.2f", sum, avg);

 

1. 값을 누적시킬 변수와 값의 개수를 카운팅하는 변수(0으로 초기화), 평균을 저장할 변수 선언

2. 무한루프 진입 -> while 한 사이클 안에서만 살아남는 지역변수 num에 값 저장

3. 만약 num값이 -1이라면 break하여 반복문 탈출

4. 아니라면 sum에 값 누적 후 카운팅

5. 루프 탈출 후 평균 계산 (이때 sum이나 numCount둘 중 하나를 반드시 명시적으로 형변환 해줘야함!!)

6. 결과값 출력.

 

입력
3
2
1
-1

실행결과
total: 6
avg: 2.00

우선 위의 코드에서 가장 중요하고 강조드리고 싶은 부분은 종료조건입니다.

종료 조건이 반드시 특정 상황에서 충족되도록 만들어야 버그를 없앨 수 있기 때문입니다.

 

또한 num변수는 while사이클이 시작할때 생성되며 다음 사이클로 넘어갈 때는 소멸됩니다. -> 지역변수 개념(중요)

 

그리고 5번에서 평균값을 구할 때는, '/'의 양쪽 피연산자 모두가 정수일 경우 몫만 반환하므로 둘 중 하나를 float로 명시적 형변환 해주어야 합니다.

 

 

 


 

반복문은 프로그래밍에서 정말정말 중요한 부분입니다. 특히 중첩 반복문은 바로바로 구조를 짤 수 있을 때까지 연습하는 것이 좋습니다. 무한 루프도 코딩을 할 때 아주 많이 써먹는 테크닉이기 때문에 중요합니다.

절대 예제를 외우려고 하지 마시고, 본질을 파악하려고 노력하셔야 합니다.

다음 문제풀이 강좌도 많이 참고해 주시고, 피드백 사항이나 질문은 댓글로 달아주세요!(공감도 정말 큰 힘이 됩니다.)

감사합니다.