4-2.for 반복문

4-2-가.for문

반복문은 비슷한 명령들을 여러 번 실행하는 제어 구조이다. 컴퓨터가 처리하는 데이터가 원래 반복적인 성격을 가지고 있기 때문에 반복문은 아주 많이 사용된다. 사실 컴퓨터가 제일 잘 하는 일이 아무 생각없이 주어진 명령을 계속 반복해 대는 것이다. 생각이 없다보니 속도도 빠르고 같은 일을 계속 시켜도 불평이 없다.

1번 학생부터 60번 학생까지 총점과 평균을 구하는 프로그램을 작성해야 한다면 똑같은 과정을 60번 반복해야 한다. 각 계산에서 달라지는 것은 학생의 번호뿐이며 총점을 구하는 방법이나 평균을 구하는 공식이 달라지는 것은 아니다. 이럴 때는 똑같은 처리를 60번 나열하는 것보다 한 번만 작성해 놓고 이 처리를 60번 반복하도록 하는 것이 훨씬 더 간단하다.

프로그램에서 이렇게 반복되는 부분을 루프(loop)라고 한다. 루프를 구성하는 방법에는 여러 가지가 있는데 C언어의 기본적인 반복문은 for문이다. for문의 형식은 다음과 같다.

 

for (초기식;조건식;증감식) 명령;

 

초기식 : 반복문은 보통 특정 변수가 일정한 범위에 있는 동안에 실행된다. 이때 반복문을 통제하는 변수를 제어 변수라고 한다. 초기식은 제어 변수의 초기값을 지정하며 루프가 시작될 때 한 번만 수행된다. i=0 이나 count=3 같은 대입문의 형식을 가지는 것이 보통이다.

조건식 : 반복문이 언제까지 실행될 것인가를 지정하며 이 조건이 참인동안 계속 루프를 돈다. 루프 실행을 계속할 계속 조건(탈출 조건이 아니라)이므로 조건이 거짓이 되면 루프를 탈출한다. 조건을 나타내므로 i < 10 또는 count < 100와 같은 제어 변수에 대한 비교 연산문이 온다. 조건문은 루프가 실행될 때마다 계속 평가된다.

증감식 : 한 번 루프를 돌 때 제어 변수를 얼마나 증감시킬 것인가를 지정한다. i=i+1 같이 제어 변수의 값을 변화시키는 연산문이 온다. 루프가 한 번 실행될 때 증감식도 한 번 실행된다.

명령 : 반복 실행될 명령이다. 하나의 명령이 올 수도 있고 { } 로 둘러싸인 복문이 올 수도 있는데 반복적인 처리는 보통 복문인 경우가 많다. 설사 루프에 포함된 명령이 하나뿐이더라도 실수 방지와 확장 편의성을 위해 가급적이면 { } 괄호를 싸 복문을 구성하는 것이 좋다.

 

앞에서 배운 if문에 비해서는 구조가 조금 복잡하다. 그러나 실제로 써 보면 아주 간단 명료하다는 것을 알 수 있을 것이다. 구체적인 예제를 만들어 보도록 하자.

 

: for

#include <Turboc.h>

 

void main()

{

     int i;

 

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

          printf("숫자 = %d\n",i);

     }

}

 

이 예제는 0~9까지 숫자를 계속 출력하기만 한다. 출력 결과는 다음과 같다.

 

숫자 = 0

숫자 = 1

숫자 = 2

숫자 = 3

숫자 = 4

숫자 = 5

숫자 = 6

숫자 = 7

숫자 = 8

숫자 = 9

 

제어 변수로 사용할 정수형 변수 i를 먼저 선언했다. 관습적으로 for문의 제어 변수는 i라는 이름의 정수형 변수를 가장 많이 사용한다. 루프로 들어가기 전에 초기식에서 i에 0을 대입하여 최초 제어 변수를 0으로 초기화했다. 그리고 조건식을 점검해 보니 i가 10보다 작은 동안 실행하라고 되어 있으므로 루프 안으로 들어간다. printf문에 의해 "숫자 = 0"이 출력된다.

다음 루프를 돌기 전에 증감식 i=i+1이 실행되어 i값이 1증가하여 1이 된다. 다시 조건식을 평가해 보니 아직도 i는 10보다 더 작다. 그래서 다시 루프가 실행되며 "숫자 = 1"이 출력된다. 이런 식으로 루프를 계속 돌아 i가 10이 되면 조건식이 거짓이 되므로 루프를 탈출한다. 조건식이 i가 10보다 작은동안이므로 10은 반복 대상에서 제외되며 루프가 끝났을 때 i값은 최초로 i < 10 조건식이 거짓이 되는 10의 값을 가질 것이다. i가 0부터 시작했으므로 printf문은 총 10번 반복되었다.

이 예제는 for문의 기본적인 사용 방법을 보여주기는 하지만 실용성은 전혀 없다. 이제 1~100까지 정수의 합을 계산하는 좀 더 실용적인 가치가 있는 예제를 만들어 보자. 아주 고리타분한 문제이지만 루프의 개념과 실용성을 설명하는 가장 좋은 예제이다.

 

: forsum

#include <Turboc.h>

 

void main()

{

     int i, sum;

 

     sum=0;

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

          sum=sum+i;

     }

     printf("1~100까지의 합 = %d\n",sum);

}

 

실행 결과는 다음과 같다.

 

1~100까지의 합 = 5050

 

기본 문법에 대해서 이미 다 설명했으므로 이 예제는 사실 설명을 읽지 않고도 스스로 이해하는 사람들이 많을 것이다. 하지만 프로그래밍을 처음 하는 사람에게 이 예제가 그다지 만만하지는 않다. 통째로 외우고 다녀도 손해 보지 않을 정도로 기본적인 예제이다. 실행 순서대로 차근 차근 분석해 보도록 하자.

 

첫 행에서 정수형 변수 i와 sum을 선언했다. 컴파일러는 두 변수에 각각 4바이트씩을 할당하며 초기값을 주지 않았으므로 이 변수들은 일단은 쓰레기값을 가진다.

sum=0; 대입문에 의해 sum이 0으로 초기화된다. sum은 결과값인 총합을 저장할 변수이므로 최초 0의 값을 가져야 한다. 이 변수에 1부터 순서대로 값을 누적시킬 것이다.

다음 줄에서 for 루프가 시작된다. 제어 변수는 i이며 초기식에서 1이 대입되었다. 1부터 100까지 합계를 구하는 문제이므로 초기값은 1이다. 조건식은 i가 100보다 작거나 같은 동안이므로 i가 100을 초과할 때까지 루프가 실행될 것이다.

for문의 명령인 sum=sum+i; 대입문에 의해 sum에 i값이 누적된다. sum=sum+i; 대입문은 sum이 원래 가지고 있던 값에다가 i를 더해서 다시 sum에 대입하라는 뜻이다. 최초 sum이 0이었고 i는 1이었으므로 sum=0+1=1이 될 것이다.

여기까지 루프를 한 번 돌았다. 명령을 실행한 후 증감식이 실행되는데 증감식은 i=i+1로 되어 있다. 증감식은 i를 1 증가시키며 i는 2가 된다. 다음 루프를 계속 돌 것인가를 판단하기 위해 조건식을 평가해 보니 아직 i가 100을 초과하려면 한참 멀었다. 그래서 다시 루프를 돈다.

sum=sum+i가 다시 실행된다. 앞의 루프에서 sum은 1이 되었는데 이번에는 sum의 값에 다시 i 를 더해 sum=1+2=3이 될 것이다. 다음번 루프를 돌때는 sum=3+3=6이 되고 그 다음번 루프를 돌때 sum=6+4=10이 된다. 이런 식으로 i가 1씩 증가하면서 루프를 돌 때마다 sum에 i가 더해짐으로써 sum에 i가 계속 누적되는 것이다.

이 루프는 i가 100보다 작거나 같은 동안에 계속 반복된다. 그래서 루프를 다 돌았을 때 sum=1+2+3+4+5+...+100;의 결과값을 가지는 것이다.

마지막 루프를 돈 후에 i=101이 될 것이고 그러면 조건식 i<=100이 거짓이 되어 루프를 탈출한다. 루프가 끝나면 마지막에 있는 printf가 sum의 값을 화면으로 출력하고 프로그램은 종료된다.

 

아주 짧은 예제이지만 실행 순서가 나름대로 복잡하다. 순서도로 프로그램의 흐름을 시각화하여 정리해 보도록 하자.

순서도를 보면 알겠지만 초기식은 루프에 들어가기 전에 한 번만 실행되고 증감식은 루프의 끝에서 매번 실행되며 조건식은 각 루프의 처음에서 매번 평가된다. for 문은 다음과 같은 if문으로 대체할 수 있다.

 

초기식;

if (조건식) {

     명령;

     증감식;

     goto if문 처음으로;

}

 

goto문은 아직 배우지 않았지만 강제로 제어를 지정한 곳으로 옮기는 명령이다. for문은 이런 강제분기문과 조건 판단문을 좀 더 사용하기 쉽도록 형식성을 갖추어 정리해 놓은 문장이다. 이 장 처음에 보인 comedycode 예제와 똑같은 동작을 하지만 이 예제는 제어 구조를 제대로 활용했으므로 변형 및 확장이 아주 용이하다. 1~1000까지 합을 구하려면 조건식만 i <= 1000으로 수정하면 되고 짝수의 합만 구하고 싶다면 초기값을 2로 주고 i=i+1을 i=i+2로 고치면 된다.

C의 for문은 굉장히 융통성이 많다. 초기식, 조건식, 증감식 각각이 일반적인 문장이기 때문에 꼭 제어 변수와 관련되지 않더라도 임의의 명령을 식으로 사용할 수 있다. 또한 정수가 아닌 실수나 포인터 등 임의의 타입을 제어 변수로 사용할 수도 있다. 이에 비해 베이직이나 파스칼의 for문은 이런 융통성을 제공하지 않는다. 다음에 for문의 몇 가지 활용예를 보인다.

 

for (i=1;i<=100;i=i+2)               // 1~100사이의 모든 홀수에 대해 반복

for (i=100;i>0;i=i-1)                 // 100~1까지 1씩 감소하며 역순으로 반복

for (f=0.1;f<=10.0;f=f+0.1)              // 0.1~10.0까지 0.1씩 증가하며 반복

 

제어 변수로 실수를 사용할 수도 있으므로 미세한 값에 대해 루프를 돌 수도 있고 제어 변수를 감소시킬 수도 있으므로 역순으로 루프를 도는 것도 가능하다. 뿐만 아니라 각 식에 함수 호출도 가능하며 다음 장에서 배울 쉼표 연산자를 사용하면 두 개의 제어 변수로 루프를 돌릴 수도 있다.

1~100까지 합계를 구하는 예제는 변수의 개념과 활용 방법, 그리고 루프에 대한 기본적인 개념을 설명하는 아주 전형적인 예제이다. 이 예제의 소스를 보지 말고 처음부터 직접 복원해 보아라. 코드를 외우지 않았더라도 논리를 이해했다면 복원이 가능할 것이며 반면 달달 외웠더라도 이해를 하지 못했으면 복원하기 어렵다. 복원까지 했다면 내친김에 응용도 해 보도록 하자.

 

 forsum2

정수 하나를 입력받아 1부터 입력받은 정수까지의 합을 출력하라. 예를 들어 10이 입력되었으면 1 ~ 10까지의 합인 55를 계산해야 한다. 합계를 누적하는 방법은 앞의 예제와 동일하며 루프만 조금 변형하면 된다.