C 언어 | 흐름 제어 | for문

for 문에 대해 설명한다. for 문은 반복 횟수를 계산하기 위한 변수의 초기화나 증가를 구문으로 작성할 수 있다.

카운터 제어 루프

기본적으로 반복 처리는 while 문만 알고 있다면 충분히 사용할 수 있지만, 대부분의 프로그래머는 앞으로 소개하는 for 문을 많이 사용하고 있다. for 문은 조건식 외에 카운터 변수의 초기화 및 계산 처리를 관리해주는 편리한 제어문이다.

for 문

for (초기화 식; 조건식; 루프 식) 문장

조건식이 참이면 문장을 반복한다는 점에서는 while과 같다. 초기화 식은 for 루프가 시작되기 전에 한번만 계산되는 식으로, 보통은 루프 제어를 이용하기 위한 카운터 변수 등을 초기화하는데 사용한다. 루프 식은 문장을 반복할 때마다 계산되는 식으로 카운터 변수를 증가하거나 감소하는데 사용된다. 이것은 다음의 while 문을 이용한 프로그램과 동일하다.

초기화 식;
while (조건식) {
  문장;
  루프 식;
}

대부분의 경우 while 문에서 반복 처리하는 때에 루프 제어를 위해 카운터를 이용한 위와 같은 구조이다. for 문은 이러한 구조를 완전한 구문으로 규정하고 있기에 대부분의 프로그래머는 적극적으로 for 문을 이용하고 있다.

또한 for 문은 초기화 식, 조건식, 루프 식 모두 생략할 수 있다. 조건식을 생략하면 항상 참으로 해석되기 때문에 무한 루프이다. 이 경우 break 문을 사용하여 빠져 나올 수 있는 대책이 필요하다. 다만 생략하는 경우는 세미콜론;을 생략할 수 없다. 예를 들어, 모든 식을 생략하는 for 문은 for (;;) {...와 같이 기술해야 한다.

코드1

#include <stdio.h>

int main() {
 int iMax , iCount;
  printf("반복 횟수를 입력하십시오. >");

 for(scanf("%d" , &iMax) , iCount = 0 ; iCount < iMax ; iCount++)
    printf("%d번째 반복입니다.\n" , iCount);
  return 0;
}

코드1은 입력된 횟수만큼 for 문을 이용하여 표시 처리를 반복하는 간단한 프로그램이다. 그러나 이 프로그램은 조금 짓궂은 소스 부분이 있다. 그것은 for 문의 초기화 식의 부분에 scanf ( "%d", &iMax), iCount = 0이다. 이 문장에는 쉼표가 2개 있지만, 사실은 이것들은 같은 쉼표로 C 언어 구문에 다른 성질을 가지고 있다. 즉, 이질적인 기능을 가지고 있다.

scanf ( "%d", &iMax), iCount = 0이라는 식의 두 쉼표의 차이에 대한 질문에 제대로 대답할 수있는 프로그래머는 그렇게 많지 않다. 사실 쉼표는 단순한 구분으로서 이용하는 경우와 수식 연산자로 사용할 수 있다. scanf("%d", &iMax)라는 문장안에 있는 쉼표 연산자가 아니다. 이것은 구분 기호이다.

이에 대해서 식에서 사용된 경우는 순차적으로 수행하는 콤마 연산자로써 기능을 한다. 이 쉼표의 사용법은 매우 희소하다. 콤마로 분리된 수식은 반드시 왼쪽에서 오른쪽으로 수행된다. 순차적으로 콤마 연산자의 연산 결과는 오른쪽 피연산자와 같은 값과 형식을 갖는다. 피연산자는 모든 타입을 지정할 수 피연산자 간의 형식 변환되지 않는다.

for 문의 초기화 식이나 루프 식으로 여러 수식을 수행하려면 코드1과 같이 순차적으로 콤마 연산자를 이용하여 여러 식을 지정할 수 있다.

그러나 일반론으로서 순차적인 콤마 연산자를 적극적으로 사용하는 것은 피해야 한다고 생각한다. 서로 밀접하게 관련 구문이거나, 여러 줄의 계산을 어떻게 해서든 하나의 문장으로 서술해야 하는 경우라면 사용해도 좋다. 예를 들어, 두 변수의 내용을 교환하는 프로그램을 만드는 경우 등에 이용하는 것도 적당하다.

코드2

#include <stdio.h>

int main() {
 int iVar1 = 100 , iVar2 = 200;
  iVar2 ^= iVar1 , iVar1 ^= iVar2 , iVar2 ^= iVar1;
 printf("iVar1 = %d : iVar2 = %d\n" , iVar1 , iVar2);

 return 0;
}

이 프로그램은 변수 iVar1과 iVar2의 값을 교환하여, 그 결과를 표시하는 것이다. 값의 교환 알고리즘은 순차적으로 콤마 연산자를 사용하여 하나의 식으로 표현하고 있다. 그런데 이 프로그램에서도 조금 심술 궂은 소스가 있다. 일반적으로 변수 값의 교환은 임시 저장용 변수를 정의하고 다음과 같이 이루어지는 것이 일반적이다.

iTmp = iVar1 , iVar1 = iVar2 , iVar2 = iTmp;

그러나 코드 2에서는 배타적 논리합의 성질을 잘 이용하고, 임시 저장용 변수를 준비하지 않고 교환을 실시하고 있다. 주제에서 벗어나는데 이렇게 연구함으로써 프로그램의 요구에 적합한 처리를 실현할 수 있을 거에요.

그러나 코드2는 배타적 논리합의 성질을 잘 이용하여, 임시 저장을 위한 변수를 제공하지 않고 교환을 수행하고 있다. 본론에서 벗어났지만, 이렇게 연구하여 프로그램의 요구에 적합한 처리를 실현할 수 있게 되었다.

이야기를 본론으로 되돌아와서, 코드2와 같이 순차적인 콤마 연산자를 사용하여 하나의 문장으로 여러 식을 계산시킬 수 있었다. 하지만 역시 먼저 말한대로 순차적으로 콤마 연산자를 적극적으로 사용하는 것은 피해야하며, 이 경우에도 하나의 문장으로 표현하는 것에 의미는 없다. 오히려 다음과 같이 기술하는 것이 일반적이다

iVar2 ^= iVar1 ; iVar1 ^= iVar2 ; iVar2 ^= iVar1;

이것은 하나의 표현이 아니라 세미콜론으로 3개의 문장으로 나누어져 있다 만, 이것으로 문제가 발생하지 않는다. 오히려 이 작성법이 일반적이기 때문에 많은 프로그래머에게는 이쪽이 더 읽기 쉽다고 느낄것이다.

for 문도 while과 마찬가지로 중첩될 수 있다. 물론 break 문이나 continue 문을 사용할 수도 있다. 복잡한 계산이나 처리에는 반드시라고 할 정도로 반복 처리가 필요하기 때문에 for 문이나 while 문 사용법은 확실히 마스터한다. 다음 프로그램은 while 문으로 만든 구구단 표를 for 문으로 만든 것이다.

코드3

#include <stdio.h>

int main() {
 int iOp1 , iOp2;

  for(iOp1 = 1 ; iOp1 < 10 ; iOp1++) {
    for(iOp2 = 1 ; iOp2 < 10 ; iOp2++) {
      printf("%2d " , iOp1 * iOp2);
   }
   printf("\n");
  }
 return 0;
}

while을 사용하는 경우에 비해, 적은 소스 줄이 스마트해진 것을 느껴졌을 거라고 생각한다. while의 경우는 복합한 문장의 내부에서 증가 및 초기화 등의 작업을 수행해야 했지만, for를 사용하면 이들을 초기화 식이나 루프 식으로 구성할 수 있다. 많은 프로그래머들이 적극적으로 for를 사용하는 이유를 이제 알았다고 생각된다.