Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

소개

이번 장에서는 C 프로그램에서 사용되는 여러가지 종류의 흐름제어(Control of flow)어 알아보도록 하겠다. 흐름제어는 주어지는 조건에 따라서 프로그램의 흐름을 제어하기 위한 목적으로 사용된다. 간단한 예로 성인인증을 위한 프로그램을 만든다고 하면, 나이를 기준으로 18세 이하면, 경고메시지를 출력하게 하고, 18세 이상이면 ok 사인을 보내는 등의 흐름제어가 필요하다.

attachment:flow1.png

위의 이미지를 보면 알겠지만, 흐름제어를 위해서는 거짓을 확인하기 위한 논리적 판단이 필요함을 알 수 있다. 때문에 흐름제어와 함께, 논리표현까지 자연스럽게 다루게 될 것이다.

어떤 조건에 따라서, 프로그램의 흐름을 달리하고자 할때 사용한다. 이면 이쪽으로, 거짓이면 저쪽으로 정도로 이해할 수 있겠다.

if

if 문은 다음과 같은 3가지 형식 중 하나를 가진다.
if (expression) statement

if (expression) statement
else statment

if (expression) statement
else if (expression) statement2
...
else statementN
if문은 매우 직관적이다. 만약 ~이면 ~을 행하라. 그렇지 않으면 ~을 행하라이다. expression에는 분기를 위한 논리조건인 ~이면에 해당하는 문맥이 들어간다. 위의 성인인증예를 if문으로 표현하자면 아래와 같을 것이다. 아래의 코드는 컴파일 후 실행이 되는 완전한 코드다.
<stdio.h>

int main()
{
	int age;
	age = 19;
	if (age >= 18)             // expression
	{                          // --+
		printf("성인 입니다.");  //   |-- statement
	}                          // --+
	else
	{                          // --+
		printf("너무 어리네요"); //   |-- statement2
	}                          // --+
	return 0;
}

위의 경우에는 조건이 하나였다. 하지만 18세 가능에 더불어 15세 가능이라는 또다른 조건이 들어갈 수 있을 것이다. 이 경우에는 여러개의 조건이 사용되게 되는데, 이때에는 3번째형식을 사용하면 된다. 3번째 형식을 사용하게 되면 조건이 몇개라하더라도 거기에 맞는 코드를 실행시킬 수 있다. 위의 셈플코드를 15세 인증까지 가능하도록 바꾸어 보자.
<stdio.h>

int main()
{
	int age;
	age = 16;
	if (age >= 18)
	{                        
		printf("성인 입니다.\n");
	}                       
	else if ((age >=15) && (age < 18))
	{                      
		printf("15세 이상 컨텐츠를 이용할 수 있습니다\n");
	}
	else
	{
		printf("나이를 좀 더 먹고 오세요\n");
	}
	return 0;
}

while 문

구체적이지 못한 추상적인 문제도 효과적으로 풀어내는 인간과 달리, 1과 0만을 구분할 수 있는 컴퓨터는 인간처럼 감각적으로 문제를 풀 수가 없다. 여러분의 눈앞에 1부터 k까지의 13장의 카드가 있다면, 여러분은 직관의 능력을 이용해서 어렵잖게 재배치를 할 수가 있다.

그러나 컴퓨터는 그렇게 하지 못한다. 컴퓨터로 이런일을 하려면 카드를 한장씩 일일이 비교해서 참인지 거짓인지 확인해서 배치를 하는 반복적인 작업을 해야만 한다. 그래서 while, do, for 와 같은 루프문이 필요하게 되며, 모든 언어를 통해서 프로그래밍을 할때, 가장 중요하며, 가장 자주 사용되는 요소이기도 하다. if 문과 while 문만 알아도 프로그램을 짤 수 있다는 얘기가 여기에서 나온다.

이러한 루프문중 가장 널리 쓰이는 while문에 대해서 우선 알아보도록 하겠다. while은 다음과 같은 형식을 가진다.
while(expression)
{                           // ---+
	// 필요한 작업을 한다.          |--- 루프 블럭
}                           // ---+
expression결과가 참이면 계속적으로 주어진 작업을 하는 식이다. 빠른 이해를 위해서 1부터 100까지 값을 더하는 프로그램을 만들어보자.
int main()
{
	int i = 0;
	int sum = 0;
	while(i < 101)
	{
		sum = sum + i;
    i++;
	}
	printf("%d\n", sum);
}
이 프로그램은 다음과 같은 흐름을 가지게 된다.
 1. i에 0을 대입한다.
 2. i와 101을 비교한다. 
 3. 0이 101보다 작으므로(결과가 참이므로) 
 4. sum = sum+i 코드를 수행한다. <--+
 5. i++을 했으므로 i는 1이된다.     |--> 루프 블럭의 코드를 반복 수행
 6. i와 101을 비교한다.             |
 7. 1이 101보다 작음으로 -----------+
 8. i가 101이 되면 i<101이 거짓이 되고 비로서 루프를 빠져나온다.

do while 문

조건검사를 블럭의 마지막에서 한다는걸 제외하면 while루프문과 완전히 동일하다.
do {

  // 필요한 작업을 한다.

} while (i < 100);
위의 while문 예제를 do while을 써서 바꾸어 보자.
int main()
{
  int i = 0;
  int sum = 0;
  do {
    sum = sum+i;
    i++;
  } while( i < 101);
  printf("%d\n", sum);
}
do while과 while은 완전히 동일하게 사용할 수 있다. 둘 중 어떤 것을 사용할런지는 개인의 코딩취향에 영향을 받는 경우가 많다. 보통은 do while 보다는 while문을 많이 사용한다.

다음은 do while문을 사용한 또 다른 예이다.
#include <stdio.h>

int main()
{
   int input;

   do
   {
       printf("Menu ====================\n");
       printf("1. Make a new account\n");
       printf("2. Delete a new account\n");
       printf("3. Deposit\n");
       printf("4. Withdraw\n");
       printf("5. Exit\n");
       printf("> ");
       scanf("%d", &input);
   } while((input > 0 && input < 6) || (input == 5));
   return 0;
}
위 프로그램은 메뉴를 출력하는 프로그램이다. scanf()함수는 키보드로 부터 입력을 받는 함수다. 이러한 메뉴프로그램의 경우 조건검사를 루프의 마지막에 하는게 더욱 자연스러운데, 이럴 경우 while문 보다 do while문을 사용하면 더 보기 좋은 코드를 만들 수 있기 때문이다.

for 문

조건을 만족하는 동안 루프를 순환한다.
for (initialize; check; update) 
{
	// 필요한 작업을 한다.
}
  • initialize : 검사할 값을 초기화 한다.
  • check : 조건을 만족하는지 검사한다.
  • update : 검사할 값을 update한다.
예를 들어 위의 1부터 100까지 더하는 while문으로된 프로그램은 다음과 같이 바꿀 수 있다.
int i=0;
int sum=0;
for (i = 0; i <= 100; i++)
{
	sum=sum+i;
}
printf("%d\n", sum);
for (i = 0; i <= 100; i++)문을 해석해 보자면, i에 0을 넣어서 초기화 하고, i가 100보다 더 작으면 루프문을 계속수행하라. 루프문을 수행했다면 i에 1을 더한다. 정도로 해석할 수 있다. 어떻게 보면 while문을 좀 더 단순하게 표현했다고 볼 수 있는데, 실제 while이나 do while문에 비해서 문장이 한눈에 잘 들어온다.

예를들어서 무한루프를 돌면서 변수에 1씩 더해주는 프로그램은 forwhile문을 이용해서 아래와 같이 동일하게 코딩할 수 있다.
// while 버젼
int i = 0;
while(1)
{
	printf("%d\n",i);
	i++;
}

// for 버젼
for(i=0;;i++)
{
	printf("%d\n",i);
}
대부분의 경우 for 문을 사용할지 while문을 사용할지는 순전히 개인의 기호에 따라 나뉜다.

switch 문

if문의 단점이라면, 조건이 여러개일 때 소스코드가 어지러워진다는 점이 될 것이다.
if (expression) statement
if else (expression) statement2
if else (expression) statement3
...
else statementN
이걸 switch를 이용하면 좀더 깔끔하게 바꿀 수 있다. switch문은 다음과 같은 형식을 가진다.
switch(expression)
{
	case (const1): statments
	case (const2): statments2
	case (const3): statments3
	default:
}

break문

switch 문을 이용하면, 몇몇 경우에 있어서 좀더 깔끔한 조건 분기의 처리가 가능하겠지만 한가지 문제점이 있다. 그것은 case를 한번 만족하게 되면, 하위 case의 조건을 검사하지 않는 다는 점이다. 즉 전부 이 되어버리는 문제가 발생한다.

int main()
{
  int menu=2;

  switch(menu)
  {
    case (1):
      printf("1. insert\n");
    case (2):
      printf("2. delete\n");
    case (3):
      printf("3. update\n");
    case (4):
      printf("4. quit\n");
    default:
      printf("error : unknown\n");
  }
}
변수 menu에 2가 대입되었으므로, 우리는 case (2)의 문맥만 실행되기는걸 예상할 수 있겠지만, case (2), case (3), case (4), default 문까지 몽땅 실행 되어버리는걸 확인할 수 있다. break; 문을 이용하면 해당 루프를 즉시 빠져나오게 됨으로 이러한 문제를 해결할 수 있다.

루프의 순환을 중단하고 즉시 빠져나온다는 break의 특성은 while, for 등의 루프문에서도 사용할 수 있다. 다음은 1부터 100까지 더하는 연산을 break 문을 통해 구현한 예다.
int i = 0;
int sum = 0;
while(1)
{
  sum += i;
  if (i == 100)
  {
    break;
  }
  i++;
}
printf("Result : %d\n", sum);

continue

루프의 수행 중에 continue를 만나게 되면, continue의 아래코드를 건너뛰고, 즉시 루프의 처음으로 되돌아간다.
while(...) <------+
{                 |
  ...             |
  if (...)        |
  {               |
    continue; ----+
  }
  ...
  ...
  ...
}

다음은 1에서 100까지의 숫자에 포함된 모든 짝수를 더하는 프로그램이다.
#include <stdio.h>

int main(int argc, char **argv)
{
  int i =0;
  int sum = 0;
  for(i=0; i < 101; i++)
  {
    if (i%2 != 0)
      continue;
    sum += i;
  }
  printf("Sum : %d\n", sum);
}

프로그램의 가독성

continue와 break문은 루프를 빠져나오거나 특정한 코드를 뛰어넘기 위한 매우 쉬운방법을 제공하지만, 코드의 가독성을 해친다는 이유로 가능하면 사용하지 않는걸 권장한다. 프로그램의 규모가 커지고, 공동작업을 하는 경우가 많아지다 보니, 특히 남이 알아보기 쉬운 코드를 작성하는 것도 중요한 일로 간주되고 있다.

코드든 다른 것이든지 간에, 가능하면 흐름이 끊기지 않고 이어지는 방향으로 나아가는게, 인간지향적인 환경을 만들어준다. 트로트 감상하는 중인데, 힙합이 튀어나오면 아무래도 당황스러울 것이다. continue와 break문은 루프의 흐름을 끊어버리는 점에서 사용하기에 편리할지는 모르지만 인간지향적이지는 않은 방법으로 이는 가독성을 떨어트리는 결과로 나타나게 된다. 그러므로 필요한 경우가 아니면 이들 문은 사용하지 않는 것을 권장 한다.

위의 짝수를 더하는 프로그램과 같은 경우 아래와 같이 continue를 사용하지 바꿀 수 있을 것이다.
  for(i=0; i < 101; i++)
  {
    if (i%2 == 0)
      sum += i;
  }