분기의 가장 기본은, if~else문이다. 이 중 첫번째 키워드인 if는 독립적으로 사용되어 조건적 실행을 가능하게 한다.
int main(void)
{
int opt;
double num1, num2;
double result;
printf("1.덧셈 2.뺄셈 3.곱셈 4.나눗셈 \n");
printf("선택? ");
scanf("%d", &opt);
printf("두 개의 실수 입력: ");
scanf("%lf %lf", &num1, &num2);
if(opt==1)
result = num1 + num2;
if(opt==2)
result = num1 -num2;
if(opt==3)
result = num1 * num2;
if(opt==4)
result = num1 / num2;
printf("결과: %f \n", result);
return 0;
}
위의 예제 자체는 어렵지 않지만, 어떠한 숫자가 입력되든 if문의 조건검사(비교연산)는 모두 실행된다는 것이다. 예제에 존재하는 4개의 if문 중 하나만이 조건을 만족하게 되어있는데, 이를 모두 실행하면 비효율적이기 때문이다.
따라서 조건을 만족하는 if문이 발견된다면, 나머지 if문을 건너뛰는 구현을 하는 것이 효율적이다. 그리고 이러한 형태의 연산을 위해서 필요한 것이 if~else문이다.
키워드 else는 독립적으로 사용되는 것이 아니라 키워드 if와 더불어 하나의 문장을 구성하는 형태로 사용된다. if와 else가 만나서 이루는 문장의 수는 둘이 아니라 하나이다.
if(num1>num2) // num1>num2이 '참'이면 아래의 if블록 실행
{
printf("num1이 num2보다 크다. \n");
}
else // num1>num2이 '거짓'이면 아래의 else블록 실행
{
pirntf("num1이 num2보다 크지 않다. \n");
}
즉, if절의 조건이 '참'이면 중괄호로 묶여있는 if블록이 실행되고, 조건이 '참'이 아니라면 중괄호로 묶여있는 else블록이 실행되는 것이다.
if~else문의 경우는 두 개의 블록 중 하나를 선택해서 실행하는 구조라면, if...else if...else문은 셋 이상의 블록 중 하나를 선택해서 실행하는 구조이다.
위 그림에서 보이듯이 중간에 esle if절은 얼마든지 추가할 수 있는 구조이다. 그리고 조건의 만족여부 검사는 위에서 아래로 진행되며, 하나라도 조건이 만족되어 해당 블록을 실행하고 나면, 마지막에 있는 else까지도 건너뛴다.
if...else를 이용하여 위의 예제를 수정하면, 아래와 같다.
int main(void)
{
int opt;
double num1, num2;
double result;
printf("1.덧셈 2.뺄셈 3.곱셈 4.나눗셈 \n");
printf("선택? ");
scanf("%d", &opt);
printf("두 개의 실수 입력: ");
scanf("%lf %lf", &num1, &num2);
if(opt==1)
result = num1 + num2;
else if(opt==2)
result = num1 - num2;
else if(opt==3)
result = num1 * num2;
else
result = num1 / num2;
printf("결과: %f \n", result);
return 0;
}
실행결과는 차이가 없으나, 조건이 만족되면 else이후로 건너뛰는 특징 때문에 연산의 수는 줄어들었다.
if~else문을 일부 대체할 수 있는 조건 연산자는 피연산자의 수가 세 개이기 때문에 '삼 항 연산자'로도 불린다. 조건 연산자는 기호 ?와 기호 : 으로 이루어진다.
(조건) ? data1 : data2
위의 문장에서 조건이 '참'이면 연산결과로 data1이 반환되고, 조건이 '거짓'이면 연산결과로 data2가 반환된다.
따라서 다음과 같은 형태로 조건 연산자를 구성할 수 있다.
int num3 = (num1>num2) ? num1 : num2;
이 경우, 대입 연산자보다 조건 연산자의 우선순위가 높으므로 조건 연산자가 먼저 진행된다. num1>num2가 '참'이라면 연산의 결과로 num1이 반환되어,
int num3 = num1;
형태가 된다.
반대로 거짓이라면,
int num3 = num2가 된다.
break는 반복문을 탈출할 때 사용하는 키워드이다. break문이 실행되면, break문을 가장 가까이서 감싸고 있는 반복문 하나를 탈출하게 된다.
int main(void)
{
int sum=0, num=0;
while(1)
{
sum+=num;
if(sum>5000)
break;
num++;
}
printf("sum: %d \n", sum);
printf("num: %d \n", num);
return 0;
}
위 코드는 1+2+3+...+n의 결과가 최초로 5000이 넘으면 반복문을 탈출하고, n의 값을 구하는 예제이다. n이 100이되면, sum의 값은 5050이 되고 break문을 실행하여 while문을 탈출하는 것이다.
continue문 역시 break문과 마찬가지로 반복문 안에 삽입이 된다.
반복문 안에서 위의 문장을 실행하게 되면, 실행중인 위치에 상관없이 반복문의 조건검사 위치로 이동을 한다. 조건검사 결과가 '참'이라면 반복영역을 다시 실행하게 된다.
이때, continue문의 이후 코드들은 생략을 하는 것을 주의해야한다.
int main(void)
{
int num;
printf("start");
for(num=1; num<20; num++)
{
if(num%2==0 || num%3)
continue;
printf("%d ", num);
}
return 0;
}
[실행결과]
start 1 5 7 11 13 17 19
조건문의 조건이 만족되어서 continue문이 실행되면, 이후 코드들은 실행되지 않고, 다시 조건검사를 위해 for문으로 이동한다. 따라서 예제의 실행결과는 20까지 2의 배수와 3의 배수는 출력되지 않는다.
switch문은 if...else if... else문과 비슷하게 동작하지만, 사용할 수 있는 영역은 제한적이다.
int main(void)
{
...
switch(n) // n은 switch문으로 전달되는 인자의 정보
{
case 1:
...
break;
case 2:
...
break;
case 3:
...
break;
default:
...
}
...
}
n은 정수형 변수여야 하는데 대표적으로 int형 변수가 위치하게 되고(char형도 가능), n에 저장된 값에 따라서 실행할 영역이 결정된다.
case문은 위치를 표시하는데 사용되므로 레이블(lable)이라 한다. 필요에 따라서 레이블은 얼마든지 추가할 수 있으며, case 레이블의 상수 값을 1부터 시작하지 않아도 된다. 또한 레이블의 끝에는 세미콜론이 아닌 콜론을 붙여야 한다.
default 영역은 일치하는 case 레이블이 없을 경우에 실행되는 영역으로, 불필요하다면 생략 가능하다.
case 레이블에 존재하는 break문은 case문을 탈출하는 용도로 사용된다.
break문이 존재하지 않으면, 가령 case 2로 이동했을 때 그 후의 case 3와 default 영역까지 실행하게 된다.
int main(void)
{
char sel;
printf("B 아침, L 점심, D 저녁 \n");
printf("입력: ");
scanf("%c", &sel);
switch(sel)
{
case 'B':
case 'b':
printf("Breakfast \n");
break;
case 'L':
case 'l':
printf("Lunch \n");
break
case 'D':
case 'd':
printf("Dinner \n");
break;
}
return 0;
}
위는 영어 대소문자를 가리지 않기 위하여 case B와 case b를 같은 영역으로 묶은 것이다. switch문에서 break문은 선택적으로 입력하여 원하는 프로그램을 작성할 수 있다.
분기의 수가 많아지면 가급적 switch문을 사용한다. 하지만 switch문으로 구현할 수 있는 조건의 구성에는 한계가 있기 때문에, 애매한 상황에서는 if...else if... else문을 사용한다.
goto는 프로그램의 흐름을 원하는 위치로 이동시킬 때 사용하는 키워드다. 하지만 goto의 사용에 부정적인 견해들이 많은데, 프로그램의 자연스러운 흐름을 방해한다는 이유 때문이다.
int main(void)
{
...
rabbit: // 위치지정에 사용된 rabbit이라는 이름의 레이블
...
goto rabbit; // 레이블 rabbit으로 이동
...
}
이동의 위치는 레이블로 표시하고, 해당 레이블을 대상으로 goto문을 구성하게 된다.