4-3-다.반복문 실습

앞에서 if문을 실습할 때 정수 하나를 입력받은 후 홀짝을 판별하는 if5 예제를 만들어 본 적이 있다. 이 예제는 입력된 숫자에 대해 한 번만 홀짝 판별을 하는데 이제 반복문을 배웠으니 사용자가 특정한 값, 예를 들어 0이 입력될 때까지 홀짝 판별을 반복하도록 수정해 보자. 먼저 값을 입력 받은 후에 이 값이 0인지 아닌지를 봐야 하므로 이 경우는 선실행 후평가문인 do~while문이 가장 적절하다.

 

: holjjak

#include <Turboc.h>

 

void main()

{

     int i;

 

    do {

          printf("정수를 입력하세요(끝낼 때는 0) : ");

          scanf("%d",&i);

          if (i % 2 == 0) {

              printf("%d는 짝수입니다.\n",i);

          } else {

              printf("%d는 홀수입니다.\n",i);

          }

    } while (i != 0);

}

 

정수를 입력받고 홀짝을 판별해서 메시지를 출력하는 일련의 코드를 do~while 루프로 감싸고 while의 조건문에 (i != 0)이라고 적으면 된다. 프롬프트를 출력하고 정수를 입력받은 후 홀짝 판별을 하는 코드 전체가 반복 단위임을 잘 파악해야 한다. 다음과 같이 반복 대상을 잘못 선택하면 엉터리로 동작하거나 차칫하면 무한 루프에 빠져 버릴 위험이 있다.

 

printf("정수를 입력하세요(끝낼 때는 0) : ");

do {

     scanf("%d",&i);

     if (i % 2 == 0) {

          printf("%d는 짝수입니다.\n",i);

     } else {

          printf("%d는 홀수입니다.\n",i);

     }

} while (i != 0);

 

printf("정수를 입력하세요(끝낼 때는 0) : ");

scanf("%d",&i);

do {

     if (i % 2 == 0) {

          printf("%d는 짝수입니다.\n",i);

     } else {

          printf("%d는 홀수입니다.\n",i);

     }

} while (i != 0);

 

 

do~while문은 정수 하나를 입력받아 이 값의 홀짝을 판별한 후 i값을 평가해 보고 이 과정을 계속할 것인지 그만 둘 것인지를 결정한다. i가 0이 아니면 루프를 계속 실행하고 0이면 루프를 탈출한다. 따라서 0이 입력될 때까지 이 과정을 계속 반복할 것이다.

 

정수를 입력하세요(끝낼 때는 0) : 2

2는 짝수입니다.

정수를 입력하세요(끝낼 때는 0) : 5

5는 홀수입니다.

정수를 입력하세요(끝낼 때는 0) : 0

0는 짝수입니다.

 

이 예제에서 0이라는 입력값은 홀짝 판별을 그만 두라는 뜻이다. 하지만 do~while 루프는 홀짝 판별을 한 후에 i값을 점검하기 때문에 0까지도 홀짝 판별의 대상이 된다. 만약 0에 대해서는 홀짝 판별을 하지 않고 즉시 루프를 탈출하도록 하고 싶다면 do~while문보다는 for 무한 루프가 더 적당하다. 다음과 같이 수정하면 0에 대해서는 홀짝 판별을 하지 않으며 0을 입력하는 즉시 루프를 종료한다.

 

: holjjak2

#include <Turboc.h>

 

void main()

{

     int i;

 

    for (;;) {           // 또는 while (TRUE)

          printf("정수를 입력하세요(끝낼 때는 0) : ");

          scanf("%d",&i);

        if (i == 0) {

           break;

        }

          if (i % 2 == 0) {

              printf("%d는 짝수입니다.\n",i);

          } else {

              printf("%d는 홀수입니다.\n",i);

          }

    }

}

 

scanf로 i값을 입력받은 즉시 이 값을 평가해 보고 만약 i가 0이면 이 값에 대해서는 홀짝 판별 및 메시지 출력을 할 필요없이 바로 루프를 탈출(break)하도록 했다. 루프를 끝내는 조건 점검의 앞뒤로 명령이 있는 경우 무한 루프를 구성하고 중간에서 조건 점검을 하여 break해야 한다. 무한 루프는 루프의 반복 회수는 물론이고 탈출할 시점까지 루프 내부에서 결정할 수 있기 때문에 기본적인 반복문에 비해 훨씬 더 융통성이 많다는 것을 알 수 있다. 어찌보면 무한루프가 가장 속편한 제어구조라고 할 수 있다.

다음 예제는 999가 입력될 때까지 사용자로부터 정수를 계속 입력받아 그 합계와 평균을 구해 출력한다. 사용자가 언제 999를 입력할 지 알 수 없으므로 루프의 반복 회수는 가변적이며 따라서 for문을 사용하는 것은 적당하지 않다. 루프 중간에 999가 입력되면 탈출해야 하므로 무한 루프를 사용하는 것이 좋다.

 

: sum999

#include <Turboc.h>

 

void main()

{

     int i;

     int n=0;

     int sum=0;

     double average;

 

     while (TRUE) {            // 또는 for (;;)

          printf("정수를 입력하세요(끝낼 때는 999) : ");

          scanf("%d",&i);

          if (i == 999) {

              break;

          }

          sum=sum+i;

          n=n+1;

     }

 

     if (n == 0) {

          average=0;

     } else {

          average=(double)sum/n;

     }

 

     printf("입력한 수의 총 합은 %d입니다.\n",sum);

     printf("입력한 수의 평균은 %.2f입니다.\n",average);

}

 

4개의 변수를 사용하는데 i는 사용자로부터 입력된 값을 저장하며 n은 입력된 숫자의 개수를, sum은 입력된 수의 총합을 누적시키기 위해 사용한다. average는 입력된 모든 값의 평균값을 계산하기 위한 실수이다. 전체 루프는 while (TRUE)문으로 무한 루프를 구성했으며 루프 내에서 정수를 입력받아 입력받은 값을 sum에 누적하며 n은 매번 1씩 증가한다.

사용자가 999를 입력했으면 루프를 탈출하되 이 값은 합계에 포함시키지 않도록 하기 위해 sum에 누적시키기 전에 break문으로 루프를 탈출하도록 했다. 루프가 끝나면 누적값 sum과 평균 average를 구해 출력하고 프로그램은 종료된다. 평균값은 총합을 입력된 개수로 나누면 쉽게 구할 수 있는데 이 부분에서 몇 가지 눈여겨 볼 부분이 있다.

먼저 n이 0인 경우에 대한 처리를 해야 한다. 즉, 사용자가 처음부터 999를 입력했다면 sum과 n이 모두 0이 되는데 이대로 나눗셈 연산을 하면 0으로 나누기 에러가 발생한다. 수학적으로 어떤 수를 0으로 나누는 것은 불가능한 계산이다. 어떠한 고성능 컴퓨터라도 0으로 나누기는 할 수 없으므로 n이 0인 경우는 sum/n 식을 계산해서는 안된다.

만약 0으로 나누기를 하면 프로그램은 다운되어 버린다. 그래서 n이 0인 경우는 실제 나눗셈을 하지 않고 average에 0을 대입하도록 했다. 값이 하나도 입력되지 않았으므로 평균은 더 계산해 볼 필요도 없이 0인 것이다. 나눗셈을 할 때는 항상 나누는 수가 0인 경우가 발생하지 않도록 주의해야 한다.

평균을 구하는 average=(double)sum/n; 문장에 (double)이라는 이상한 문장이 있는데 이것은 캐스트(Cast) 연산자라는 것이다. / 연산자는 피연산자가 모두 정수일 때는 소수점 이하를 계산하지 않기 때문에 sum을 잠시 실수형으로 바꾸어야 소수점 이하까지 정확하게 나눗셈을 하게 된다. 캐스트 연산자에 대해서는 다음 장에서 상세하게 다룰 것이다.