이번 Chapter에서는 사용자의 선택에 따라 진행하는 일의 형태를 분기시켜보자. (조건문)
계산기 프로그램을 구현한다고 가정했을 때 우리는 사칙연산을 선택적으로 실행 가능하게 만들어야한다.
하지만, 여태까지 학습한 방법으로는 선택적으로 원하는 연산만 골라 실행하지않고 모든 문장을 순차적으로 실행해왔다.
조건적으로 실행할 수 있게 하는 구문에는 if문
과 if~else문
이렇게 두가지가 있다.
분기의 가장 기본은 두 개의 키워드 if
와 else
로 구성되는 if~else문
이다.
그런데 이 중 첫 번째 키워드인 if
는 독립적으로 사용되어 '조건적 실행(조건에 따라서 실행을 하느냐 마느냐)'를 가능하게 한다.
if문
의 구성은 다음과 같다.
num1이 num2보다 큰 경우에만 if문의 중괄호에 삽입된 두 개의 printf함수 호출문이 실행된다.
물론 조건이 만족될 때 실행할 문장이 하나라면 중괄호 생략이 가능하다.
예제를 통해 if문 동작 방식에 대해 구체적으로 알아보자.
/* ifBsic.c 예제 */
#include <stdio.h>
int main()
{
int num;
printf("정수 입력: ");
scanf_s("%d", &num);
if (num < 0) // num이 0보다 작으면 아래의 문장 실행
printf("입력 값은 0보다 작다.\n");
if (num > 0) // num이 0보다 크면 아래의 문장 실행
printf("입력 값은 0보다 크다. \n");
if (num == 0) // num이 0이면 아래의 문장 실행.
printf("입력 값은 0이다. \n");
return 0;
}
이번엔 계산기 프로그램으로 if문에 대해 이해해보자.
/* CalOne.c 예제 */
#include <stdio.h>
int main()
{
int opt;
double num1, num2;
double result = 0.0;
printf("\n1.덧셈 2.뺄셈 3.곱셈 4.나눗셈 \n");
printf("선택? ");
scanf_s("%d", &opt);
printf("두 개의 실수 입력: ");
scanf_s("%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\n", result);
return 0;
}
여기서 문제점이 하나 있다.
어떤 숫자가 입력되던 if문에 있는 조건검사(비교연산) 4개가 모두 실행된다는 것이다!
따라서 다음과 같이 구현 가능하다면 불필요한 연산 수를 줄일 수 있어 더 효율적이다.
/* Mul3Mul4.c 예제 */
#include <stdio.h>
int main()
{
int num;
for (num = 1; num < 100; num++)
{
if (num % 3 == 0 || num % 4 == 0)
printf("3 또는 4의 배수: %d \n", num);
}
return 0;
}
이 코드에서는 조건을 만족하는 if문이 발견되면 나머지 if문은 건너뛰게 된다.
이러한 형태의 연산을 위해서 필요한 것이 바로 if~else문
이다.
그리고 위에서 for문의 중괄호도 생략이 가능하다. 왜냐면 반복하는 건 if문 하나고 그 아래 내용은 if문에 포함되어 있기 때문이다!
또한, if의 조건문에서 ||
연산자 보다 ==
연산자의 우선순위가 더 높기 때문에 ||
연산자 양 옆 연산이 먼저 이루어지고 난 뒤 ||
연산이 진행되었다는 것을 알 수 있다.
키워드 else
는 독립적으로 사용되는 것이 아니라 키워드 if
와 더불어 하나의 문장을 구성하는 형태로 사용된다.
따라서 if~else문
의 구조를 살펴보자.
if절
의 조건이 '참'이면 중괄호로 묶여있는 if 블록이 실행되고,
조건이 참이 아니면 else절
의 중괄호로 묶여있는 else 블록이 실행되는 구조다.
다음 예시를 통해 더 자세히 알아보자.
/* IfElseBasic.c 예제 */
#include <stdio.h>
int main()
{
int num;
printf("정수 입력: ");
scanf_s("%d", &num);
if (num < 0)
printf("입력 값은 0보다 작다. \n\n");
else
printf("입력 값은 0보다 작지 않다. \n\n");
return 0;
}
여기서 if 블록과 else 블록에 해당하는 문장이 하나이기 때문에 중괄호를 생략했다.
if~else문
의 경우 이지선다였다면 if~else if~else문
은 셋 이상의 블록 중 하나를 실행하는 구조다.
if...else if...else문의 구성
if...else if...else문의 흐름
위 구조와 흐름에서 주목할 부분은 두 가지다.
이러한 특징 때문에 조건이 만족되고 해당 블록을 실행하고 나면 마지막 else까지도 그냥 건너뛰게 된다. 따라서 아까의 계산기 프로그램을 개선시켜보자.
/* CalTwo.c 예제 */
#include <stdio.h>
int main()
{
int opt;
double num1, num2;
double result;
printf("1. 덧셈 2. 뺄셈 3. 곱셈 4. 나눗셈 \n");
printf("선택: ");
scanf_s("%d", &opt);
printf("두 개의 실수 입력: ");
scanf_s("%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\n", result);
return 0;
}
사실 if~else if~else문
을 하나의 독립된 문장으로 보는 경우가 많은데,
이는 if~else문
의 중첩이다.
이렇게 구분이 되고 중괄호를 삽입하여 훨씬 보기 쉽게 한다면 아래와 같다.
else 블록에 중첩으로 들어간다.
if~else문
을 일부 대체할 수 있는 조건 연산자에 대해 얘기해보자.
이 연산자는 피연산자의 수가 세 개이기 때문에 삼 항 연산자
라고도 불린다. 구조는 다음과 같다.
소괄호는 이해를 위해 넣은 것이니 생략 가능하다.
조건 연산자는 기호 ?
와 :
로 이루어진다.
조건 연산자 문장을 풀어 쓰면 아래와 같다.
위 조건이 '참'이면 연산 결과로 data1이 반환되고,
조건이 '거짓'이면 연산 결과로 data2가 반환된다.
조건 연산자가 대입 연산자보다 우선순위가 높으므로 조건 연산자가 먼저 진행되어 아래와 같은 형태로도 구성할 수 있다.
num1이 num2보다 크다면 int num3 = num1이 되겠고 num1이 num2보다 작으면 int num3 = num2가 된다.
예제를 통해 이해해보자.
/* ThreeOperand.c 예제 */
#include <stdio.h>
int main()
{
int num;
int abs;
printf("정수 입력: ");
scanf_s("%d", &num);
abs = num > 0 ? num : num * (-1);
printf("절댓값: %d \n\n", abs);
return 0;
}
조건 연산자는 간단한 if~else문을 대체할 수 있는 연산자로 자주 사용된다.
continue문
과 break문
은 while문
과 같은 반복문과 관련이 있다.
그런데 이 두 문장은 보통 if문
과 함께 쓰이므로 알아두자.
break
는 반복문을 빠져 나올 때 사용하는 키워드로 break;
라고 사용하면 된다.
break문
을 실행하면 break문을 가장 가까이서 감싸고 있는 반복문 하나를 빠져 나오게 된다.
break문
이 if문과 함께 쓰였다고 해서 if문을 빠져 나오는 것으로 이해하면 안된다!
예제를 통해 알아보자.
/*WhenOver5000.c 예제*/
#include <stdio.h>
int main()
{
int sum = 0, num = 0;
while (1)
{
sum += num;
if (sum > 5000)
break; // sum이 5000이 넘을때 반복문 sum+=num을 탈출!
num++;
}
printf("sum: %d \n", sum);
printf("num: %d \n\n", num);
return 0;
}
키워드 continue
를 이용한 문장의 구성은 continue;
이고 이 역시 break문과 마찬가지로 반복문 안에 삽입된다.
반복문 안에서 continue문
을 만나면 실행중인 위치에 상관없이 반복문의 조건검사 위치로 이동한다. 그리고 검사결과 반복조건이 여전히 '참'이라면 반복영역을 다시 실행하게 된다.
continue문
이후로 생략을 하고, 다시 실행하게 된다.
1 이상 20 미만의 정수를 출력하되, 2의 배수와 3의 배수를 출력에서 제외시키는 프로그램 예제를 보자.
/*ExceptMul2Mul3.c 예제*/
#include <stdio.h>
int main()
{
int num;
printf("start! ");
for (num = 1; num < 20; num++)
{
if (num % 2 == 0 || num % 3 == 0)
continue;
printf("%d ", num);
}
printf("end! \n\n");
return 0;
}
break문
과 continue문
의 실행 흐름은 아래와 같다.
switch문
은 if~else if~else문
과 유사한 측면이 있다.
따라서 대체하기도 하지만 switch문
은 if~else if~else문
에 비해 제한적이다.
우선 예제를 통해 switch문이 어떻게 동작하는지 생각해보자.
// EnglishSchool.c 예제
#include <stdio.h>
int main()
{
int num;
printf("\n1이상 5이하의 정수 입력: ");
scanf_s("%d", &num);
switch (num)
{
case 1:
printf("1은 ONE! \n");
break;
case 2:
printf("2는 TWO! \n");
break;
case 3:
printf("3은 Three! \n");
break;
case 4:
printf("4는 FOUR! \n");
break;
case 5:
printf("5는 FIVE! \n");
break;
default:
printf("I Don't Know! \n");
}
return 0;
}
switch문의 실행 흐름을 살펴보자.
switch(n)
에서 n은 switch문으로 전달되는 인자의 정보다. n에 저장된 값에 따라 실행할 영역이 결정된다.
case문은 위치를 표시하는데 사용되므로 '레이블(label)'이라 한다.
그리고 필요에 따라서 case 레이블은 언제든지 추가할 수 있으며, 굳이 case 레이블을 상수 값 1부터 시작하지 않아도 된다.
그리고 레이블의 끝에는 세미콜론이 아닌 콜론이 붙여 있다!⭐
마지막 하단부에는 default 레이블이 있다.
if~else if~else문
에서 마지막 else문에 해당하며 일치하는 case 레이블이 없을 경우 실행되는 영역을 표시할 때 사용된다. (필요 없으면 생략 가능하다.)
그리고 break문은 switch문을 탈출하는 용도로도 사용된다.
아래 예제를 살펴보면 break문의 필요성에 대해 알게 될 것이다.
// AdvanEnglishSchool.c 예제
#include <stdio.h>
int main()
{
char sel;
printf("M 오전, A 오후, E 저녁 \n");
printf("입력: ");
scanf_s("%c", &sel, 1);
// &sel이 가리키는 곳은 1바이트의 공간이다라는 뜻으로 뒤에 1을 붙여 줘야한다.
switch (sel)
{
case 'M': // 한줄로 case 'M': case 'm':으로 표현하기도 한다.
case 'm':
printf("Morning \n");
break;
case 'A':
case 'a':
printf("Afternoon \n");
break;
case 'E':
case 'e':
printf("Evening \n");
break; // 사실 안적어도 됨! 뒤에 default가 오지 않을거면!
}
return 0;
}
대문자 M을 입력하던 소문자 m을 입력하던 동일한 문자열이 출력된다.
이렇든 필요에 의해 break문을 삽입해도 되고 안해도 된다.
분기의 경우 수가 많아지면 가급적 switch문으로 구현한다.
if~else if~else문에 비해 간결해보이기 때문이다.
다만 조건의 구성에 한계가 있어 switch문으로 표현하기 애매한 상황에서는 if~else if~else문을 사용한다.
switch 문의 간결성
if~else if~else문 필요성
goto문
은 프로그램의 흐름을 원하는 위치로 이동시킬 때 사용하는 키워드다.
가장 큰 단점이 '프로그램의 자연스러운 흐름을 방해한다'는 것이다.
C언어와 같은 절차지향 프로그래밍 언어에서 프로그램의 흐름을 방해하거나 복잡하게 하는 것은 큰 단점이 된다.
그래서 가볍게 설명하고 넘어가려 한다.
goto문의 기본 구성
예제
// GoToBasic.c 예제
#include <stdio.h>
int main()
{
num = 0;
printf("자연수 입력: ");
scanf_s("%d", &num);
if (num == 1)
goto ONE;
else if (num == 2)
goto TWO;
else
goto OTHER;
ONE:
printf("1을 입력하셨습니다! \n");
goto END;
TWO:
printf("2를 입력하셨습니다! \n");
goto END;
OTHER:
printf("3 혹은 다른 값을 입력하셨군요! \n");
END:
return 0;
}
<Review>
python을 배울 때 조건문으로 if문
, if~else문
, if~elif~else
문만 배워 잊고 있었는데 C언어에서는 훨씬 이해하기 쉽게 직관적으로 문법이 되어있어 이해하기 쉬운 것 같다.
for문이랑 while문은 동일했지만 (물론 문법적으로 C언어가 더 직관적이라 난 C언어로 배운게 더 쉬웠다.) 조건문에서 더 다양하게 사용하는 것을 보고 다시 재미가 올랐다!
역쉬,,, 근본 언어! 아마 이제 슬슬 배열과 포인터가 나와 어려워질 내용이지만 한번만 이해하기 시작하면 그리 어렵지 않으니 힘내서 해보자~!