끝나지 않는 프로그래밍 일기


1. while, do~while, continue

 

이번에는 반복문에 대해서 살펴보도록 할텐데, 반복문의 이름에서 어떤 역할을 하는 녀석인지 대충 짐작이 가시죠? 만약에 어느 한 문장을 100번 출력하고 싶으면 어떻게 코드를 작성해야 할까요? 일일히 printf를 사용하여 100번씩이나 함수를 호출해야 할까요? 이것은 상당히 비효율적이며 보기도 안좋습니다. 그럼 어떻게 해야할까요? 이것을 우리가 배울 반복문이란 녀석이 해결해 줄수 있습니다. 이 반복문 중에서도 여러가지가 있는데, 우선은 while문에 대해 알아보도록 하겠습니다. while 문의 구성은 다음과 같습니다.

while (반복 조건) {
 반복 영역;
}

이 while문은 반복 조건이 참(TRUE)이면 계속 반복 영역에 있는 코드를 실행시키며 루프를 돌게 됩니다. 위에서 말한 문장을 100번 출력시키는 코드를 while문을 이용하여 코드로 옮기면 다음과 같습니다.

#include <stdio.h>

int main()
{
 int i=0; // i를 0으로 초기화, 초기화 하지 않으면 쓰레기값으로 초기화 됨

 while (i<100) {
  printf("호출 횟수: %d\n", i);
  i++; // 후위증가 연산자, i의 값을 1씩 증가시킴
 }

 return 0;
} 

결과:

호출 횟수: 0
호출 횟수: 1
호출 횟수: 2
..
호출 횟수: 98
호출 횟수: 99
계속하려면 아무 키나 누르십시오 . . .


위 코드를 실행하면 정확히 printf 함수가 100회 호출되는것을 확인할 수 있습니다. i를 0으로 초기화 시키고 i<100이 참일때동안 루프를 돌면서 i를 1씩 증가시키고 조건이 거짓이 되면 빠져나오도록 했습니다. 그렇게 루프를 돌면서 i가 100이 되는 순간 조건수식 i<100이 거짓이 되면서 반복문을 빠져나왔습니다. 그런데 반복 조건식이 항상 참이면 어떻게 될까요?

#include <stdio.h>

int main()
{
 while (1) { // 항상 참
  printf("무한 루프\n");
 }
 return 0;
}

결과:

무한 루프

무한 루프

무한 루프

...


5행의 반복 조건이 와야할곳에 1이 왔는데 1은 논리적으로 참(TRUE)입니다. 따라서 반복 조건이 항상 참이므로 반복 영역에 있는 코드를 계속 호출합니다. 이 무한루프는 개발자의 실수로 인해 만들어 지기도 하나, 필요에 의해 만들어지기도 합니다. 무한 루프를 탈출하려면 switch 문을 공부할때 배웠던 break 문을 사용하면 탈출할수 있습니다.


그 다음으로는 간단히 do~while에 대해 알아보도록 합시다. do~while문도 while문과 크게 차이나는 것은 없습니다. do~while문의 구성은 아래와 같습니다.

do {
 반복 영역;
} while (반복 조건);

앞에서 설명드린 while문이랑 상당히 유사하며 차이점은 반복 영역에 있는 코드를 한번 실행하고 반복 조건이 참일때동안 루프를 돕니다. while문은 반복조건이 앞에있다면 do~while은 반복 조건이 뒤에 있다고 이해하시면 됩니다.  while문을 쓰든 do~while문을 쓰든 상관이 없지만 do~while 활용이 더 적절할때가 있습니다.

#include <stdio.h>

int main()
{
 int a, sum=0;
 
 do {
  printf("값을 입력하세요: ");
  scanf("%d", &a);
  sum+=a;
} while (a!=0);
printf("합: %d\n", sum);
 return 0;
}

결과:

값을 입력하세요: 2
값을 입력하세요: 4
값을 입력하세요: 6
값을 입력하세요: 8
값을 입력하세요: 10
값을 입력하세요: 12
값을 입력하세요: 0
합: 42
계속하려면 아무 키나 누르십시오 . . .


우선 반복 영역에 있는 코드를 한번 실행하면서 사용자로부터 a의 값을 입력받고 그 a의 값을 sum에 더하고 조건이 참인지 검사한뒤에 참이면 계속 루프를 돌고 거짓이면 빠져나오게 됩니다. 이처럼 조건을 검사하기전 반복 영역을 최소한 한번은 실행시켜야 하는 상황이면 do~while를 고려해볼수도 있습니다. 

만약에 1부터 100까지의 수 중 홀수만 출력하게 하는 프로그램을 작성하려 한다면 물론 반복문을 사용하겠죠? 그런데, while문을 사용한다고 가정하여 어느 특정 조건을 만족하면 반복 영역에 있는 코드를 실행하지 않고 한 회 쉬게 한다면 어떻게 코드를 작성할 수 있을까요? 이것은 continue 라는 녀석이 쉽게 해결해 줄수 있습니다. continue란 녀석이 어떤 녀석인지 알아보기 위해 아래의 코드를 직접 실행해보고 조금 변형하여 이해를 하시길 권장하는 바입니다.

#include <stdio.h>

int main()
{
 int i=0;

 while (i<=100) {
  i++;
  if (i%2!=0) continue;
  printf("%d ", i);
 }
 printf("\n");

 return 0;
}

결과:

2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56
58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100
계속하려면 아무 키나 누르십시오 . . .


코드를 읽어보면 우선 i를 0으로 초기화 시키고 i<=100이 참일때동안 루프를 도는데 여기서 주의할 것은 i를 2로 나눠서 나머지가 0이 아니면, 즉 홀수(나누어 떨어지지 않는 경우)면 continue 라는 키워드를 만나 반복 조건을 검사하는 영역으로 돌아갑니다. 
 


그렇다면 i가 짝수일때 i%2!=0의 조건을 충족하지 못하면서 빠져나오고 그 i의 값을 출력합니다.(짝수만 출력하는 것이 됨) 많이는 사용되지 않으며 정리하자면 continue는 반복문에서 조건 점검부로 점프하여 다음 값을 실행할수 있게 만들어주는 명령입니다.

 

2. for


우리가 이제 배울 for문으로 할수있는 모든 것은 while문으로 해결할수 있으나 while 문이 적절할 때도 있고 for문의 사용이 적절할때도 있습니다. 우선 while문과 for문을 비교해 보겠습니다. while문과 for문으로 printf 함수를 10번 호출하여 문장을 출력하도록 만들어 보도록 하겠습니다.

int i=0;

while (i<10) {
 printf("%d ", i);
 i++;
}
int i;

for(i=0; i<10; i++)
 printf("%d", i);

for문이 while문에 비해 상당히 간결하다는걸 느낄수 있습니다. 초기식, 증감식, 조건식이 한줄에 모두 오며 둘다 똑같은 기능을 수행합니다. 즉 반복 횟수를 세기 위한 변수와 탈출조건, 루프를 빠져나가기 위한 연산이 한줄에 있다는 말입니다. 우리가 배우게 될 for문의 구성은 다음과 같습니다.

for (초기식; 조건식; 증감식) {
 반복 영역;
}
여기서 초기식은 반복 횟수 카운트를 저장하기 위한 변수의 초기화 부분이며 그 다음에 오는 조건식은 앞서 설명드렸던 while문의 반복 조건 영역과 같습니다. 증감식도 비슷합니다. for문의 실행 흐름을 잠시 살펴보자면 초기식을 1번, 조건식을 2번, 증감식을 3번, 반복 영역을 4번으로 두고 다음과 같은 흐름을 보입니다.

1 -> 2 -> 4 -> 3 -> 2 -> 4 -> 3 -> 2 -> 4 ....


살펴보자면 초기식이 처음 실행된다음 조건식, 반복 영역, 증감식을 반복하고 있습니다. 여기서 알수있는건 초기식은 루프를 돌때 딱 한번만 실행된다는 것을 주의하셔야 합니다. for문을 이용하여 1부터 100까지의 합을 출력해볼까요? 다음 예제를 한번 보도록 합시다.

#include <stdio.h>

int main()
{
 int i, sum=0;

 for(i=1; i<=100; i++)
  sum+=i;

printf("1부터 100까지의 합: %d", sum);
return 0;
}

결과:

1부터 100까지의 합: 5050


코드가 상당히 간단명료하며 사용하기도 생각보다 간단합니다. 코드를 읽어 보시면, 반복 횟수를 세기 위한 변수 i와, 1부터 100까지의 합을 넣을 sum이란 변수가 선언되었습니다. 그리고 나서는, for문이 사용되어 i=1(초기식)을 거치고 i가 1로 초기화 됩니다. 그리고 나서 i가 100보다 작거나 같은지 검사(조건식)합니다. 만약에 i가 100보다 크다면 조건식이 거짓이 되어 루프를 빠져나옵니다. 참이라면, 반복 영역에 있는 코드를 실행시키고 i의 값을 1만큼 증가시킵니다. (여기서 ++는 후위 증가 연산자로, 피연산자 즉 i의 값을 1만큼 증가시키는 역할을 합니다. i++는 i = i + 1의 역할을 수행하는 코드라고 생각하시면 됩니다.) 그리고 이를 조건식이 거짓이 되어 빠져나올때까지 반복을 하는 셈이죠.


참고로 우리가 앞서 배운 if문도 중첩이 가능하듯이, 반복문도 중첩이 가능합니다. 여기서 반복문이라 하면, while와 for, do~while등 여러가지가 중첩될 수 있다는 말입니다. 아래와 같이 말이죠.

for (...;...;...;) {
 for (...;...;...;) {
   ....
 }
}

for (...;...;...;) {
 while (...) {
  ....
 }
}

이밖에도 위에서 말했듯 while~for, do~while~for, while~while, do~while~while, for~do~while등 여러개의 반복문의 중첩이 가능합니다.

 

3. goto


goto 문은 지정한 곳으로 무조건 점프하는 명령을 수행하는 제어문인데 사용하기가 쉽고 아래와 같은 방법으로 사용할 수가 있습니다.

#include <stdio.h>

int main()
{
 printf("1\n");
 printf("2\n");
 goto five; // five로 점프를 시키는 명령
 printf("3\n");
 printf("4\n");
 five: // five
 printf("5\n");
 printf("6\n");
return 0;
}

결과:

1

2

5

6


왜 저러한 결과가 나오신지는 이해가 확 가시죠? 코드를 읽어보시면, 우선 1과 2를 출력하고 goto five;라는 문장을 만나 five 레이블로 건너뜁니다. 그러면 five: 부터 코드가 다시 실행되는데, 3과 4는 출력하지 못하고 5와 6이 출력되는 것입니다. 상당히 편해보이고 유용해 보이지만, goto문은 프로그램의 구조를 해치며 goto문이 많아지면 상당히 복잡해지고 부작용이 많습니다. goto 문의 사용은 가급적이면 줄이시는게 좋습니다.