이번에는 C언어에서 매우 중요한 제어문 - 그 중에서도 조건문을 배우겠다.
우리가 자판기에서 음료를 뽑을 때 다음과 같은 과정이 자판기 내부에서 진행이 된다.
돈을 넣은다, 지폐인가?, 액수가 충분한가? 이러한 질문들은 맞다, 아니다로 나뉘게 된다. 이러한 것들을 조건문이라고 한다. 즉 항상 실행되는게 아니라 조건에 맞을 때 실행되는 것이다.
그런데 위에 부분은 우리가 지금까지 보지 못했었던 특징이 있다. 예를들어서
#include<stdio.h>
int main(){
printf("안녕");
printf("만나서 반가워");
printf("나는 ***야");
return 0;
}
위와 같이 "안녕" 이 먼저 출력되고 그 뒤로 순서대로 "만나서 반가워", "나는 ***야"가 실행된다.
즉 위에서 아래로 순서대로 실행이 된다는 말이다. "만나서 반가워" 가 먼저 출력되고 "안녕"이 출력되는 일이 없다는 말이다. 단지 어떠한 조건에서든 위의 코드 순서대로 출력이 된다는 말이다.
하지만 위 그림을 보면 "지폐인가?" 부분에서 Yes면 "액수가 충분한가"가 실행되고 No 면 "동전 인가?" 가 실행 된다. 다시말해서 어떠한 조건을 만족하면 이것이 실행되고 다른 조건이면 저것이 실행된다는 말이다. 이러한 것을 조건문이라고 한다.
#include <stdio.h>
int main() {
int i;
printf("입력하고 싶은 숫자를 입력하세요! : ");
scanf("%d", &i);
if (i == 7) {
printf("당신은 행운의 숫자 7 을 입력했습니다");
}
return 0;
}
위 예제를 컴파일 한 이후에 7을 대입하면
printf("당신은 행운의 숫자 7 을 입력했습니다");
가 실행된 다음에 return 0
가 실행되고 만약 7이 아닌 다른 수를 입력하면 위 print문이 실행되지 않은채 return 0
가 실행이 된다.
if문은 언제나 괄호안에 조건이 참이라면 중괄호 내용이 실행되고 아니면 중괄호 내용이 실행되지 않고 지나치게 된다.
참고로 ==
와 같이 어떠한 두 값 사이의 관계를 나타내주는 것을 관계 연산자라고 한다. 관계 연산자 좌측에 있는 것을 좌변, 우측에 있는 것을 우변이라고 한다. 위의 같은 경우 i == 7
에서 i
가 좌변 , 7 이 우변이 된다.
또한 알아야 하는 한가지 중요한 것은 사실 관계 연산자는 어떠한 관계의 연산이 끝나고 참이면 1을, 거짓이면 0을 나타나게 된다.
다시말해서 if문은 겉으로 보기에는 참과 거짓에 따라서 내용이 실행되도 지나치는것 같지만 사실은 if문 조건이 0인가(거짓), 1인가 (참) 에 따라서 실행의 유무를 판단하게 된다.
따라서 if(0)
을 하면 중괄호 내용은 실행되지 않고 if(1)
이라고 한다면 그 중괄호 내용이 실행이 된다.
#include <stdio.h>
int main() {
double i, j;
printf("나누고 싶은 두 정수를 입력하세요 : ");
scanf("%lf %lf", &i, &j);
printf("%f 를 %f 로 나눈 결과는 : %f \n", i, j, i / j);
return 0;
}
위 예제를 컴파일후 10과 3을 입력하게 되면 아래와 같은 결과가 나온다.
나누고 싶은 두 정수를 입력하세요 : 10
3
10.000000 를 3.000000 로 나눈 결과는 : 3.333333
그런데 만약에 1과 0을 넣으면 어떻게 될까?
나누고 싶은 두 정수를 입력하세요 : 1
0
1.000000 를 0.000000 로 나눈 결과는 : inf
int
라는 이상한 결과가 나왔다. 왜일까? 왜냐하면 수학에서(즉 컴퓨터에서) 1을 0으로 나누는 행위는 금지되어 있다. 그나마 변수 i , j 를 double
형으로 선언해서 다행이지 int
형으로 선언했다면 프로그램이 오류를 내뿜고 종료되었을 것이다.
별로 대수롭지 않게 생각할 수 있지만 만약에 우리가 엑셀파일을 며칠동안 열심히 작업했는데 실수로 어떤수를 0으로 나누는 작업을 했더니 힘들게 작업한 엑셀이 종료되고 내용들이 날라가게 된다면 어떨까?
그렇기 때문에 우리는 나누는 수(제수)가 0이 아닌지 확인할 필요성이 있다. 따라서 위 프로그램을 아래와 같이 수정해보자
#include <stdio.h>
int main() {
double i, j;
printf("나누고 싶은 두 정수를 입력하세요 : ");
scanf("%lf %lf", &i, &j);
if (j==0){
printf("0을 나눌 수 없습니다.");
return 0;
}
printf("%f 를 %f 로 나눈 결과는 : %f \n", i, j, i / j);
return 0;
}
위 프로그램을 살펴보면
if (j==0){
printf("0을 나눌 수 없습니다.");
return 0;
}
여기서 만약 j가 0일 경우에는 print문이 실행되고 종료(retuurn 0
) 가 된다.
반면에 j의 값이 0이 아닐 경우에는 if문이 중괄호를 그냥 지나치게 되어 아래코드가 실행되고 프로그램이 종료한다
printf("%f 를 %f 로 나눈 결과는 : %f \n", i, j, i / j);
return 0;
#include <stdio.h>
int main() {
int score;
printf("당신의 수학점수를 입력하세요! : ");
scanf("%d", &score);
if (score >= 90) {
printf("당신은 합격입니다! \n");
}
if (score < 90) {
printf("당신은 불합격 입니다! \n");
}
return 0;
}
다음 예제를 보겠다 여기서는 만약 score
가 90점 이상이면 합격이라고 출력하고 만약 90점 미만이면 불합격이라고 출력하는 프로그램이다.
이미 짐작 했겠지만 (score >= 90)
에서 >=
는 '이상' 을 의미하고 <
는 미만을 의미한다.
여기서 주의할 점은 (score => 90)
이런식으로 조건이 주어져서는 안된다. 이럴 경우에는 컴파일러는 인식하지 못하게 된다.
만약 이 부분이 헷갈린다면 '크거나 같다' 라는 말을 말 그대로 생각하면 된다. 즉 크거(>) 나 같다(=) 이다.
score >= 90; // 90점 이상이다.
score > 90; // 90점 보다 크다. (초과)
score <= 90; // 90점 이하이다.
score < 90; // 90점 보다 작다. (미만)
score == 90; // 90점이다.
score != 90; // 90점이 아니다.
나머지 조건들도 위와 같이 있다.
앞서 if문은 조건에 맞으면 중괄호가 실행되고 아니면 그냥 넘어간다고 했었다. 그렇다면 아래와 같은 프로그램을 살펴보자.
#include <stdio.h>
int main() {
int num;
printf("아무 숫자나 입력해 보세요 : ");
scanf("%d", &num);
if (num == 7) {
printf("행운의 숫자 7 이군요!\n");
} else {
printf("그냥 보통 숫자인 %d 를 입력했군요\n", num);
}
return 0;
}
자세히 살펴보면
if (num == 7) {
printf("행운의 숫자 7 이군요!\n");
} else {
printf("그냥 보통 숫자인 %d 를 입력했군요\n", num);
}
return 0;
이 부분에서 만약 num
이 7이 아니라면 그냥 if 문을 건너뛰고 종료(return 0
)가 될 것 같지만 사실 그렇지 않다. 왜냐하면 else
가 있기 때문이다.
else
는 조건에 맞지 않는 경우 실행되는 구문이다. 즉 num
이 7이 아니라면 else
구문이 실행된다는 뜻이다. 따라서 "그냥 보통 숫자인 %d 를 입력했군요" 가 실행이 된다. 그리고 7이면 "행운의 숫자 7 이군요!" 가 실행이 된다.
그렇다면 이 아이디어를 확장해서 다음의 프로그램을 보자
#include <stdio.h>
int main() {
int num;
printf("아무 숫자나 입력해 보세요 : ");
scanf("%d", &num);
if (num == 7) {
printf("행운의 숫자 7 이군요!\n");
} else {
if (num == 4) {
printf("죽음의 숫자 4 인가요 ;;; \n");
} else {
if (num == 1) {
printf("첫 번째 숫자!! \n");
} else {
if (num == 2) {
printf("이 숫자는 바로 두번째 숫자 \n");
} else {
......(생략)......
}
}
}
}
return 0;
}
위 프로그램은 우선 num
이 7인지 확인하고 7이 아니라면 else구문이 실행이 된다 그런데 else구문 안에서 또다른 if문이 실행이 되어 num
이 4인지 확인한다 그리고 아니면 else구문이 실행되고 다른 if구문이 실행되어 1인지 확인하고 이러한 구문이 반복이 된다.
하지만 이러한 프로그램은 보기에도 복잡하고 불편하다 그래서 C언어는 이러한 구문을 간단하게 만들었다.
#include <stdio.h>
int main() {
int num;
printf("아무 숫자나 입력해 보세요 : ");
scanf("%d", &num);
if (num == 7) {
printf("행운의 숫자 7 이군요!\n");
} else if (num == 4) {
printf("죽음의 숫자 4 인가요 ;;; \n");
} else {
printf("그냥 평범한 숫자 %d \n", num);
}
return 0;
}
바로 else if
를 사용하는 것이다. 위 프로그램은 앞서 보았던 복잡했던 프로그램과 똑같이 작동한다.
하지만 훨씬 보기 편해졌고 난잡했던 중괄호도 어느정도 정리가 된것을 볼 수 있다.
위 프로그램을 살펴보면
if (num == 7) {
printf("행운의 숫자 7 이군요!\n");
} else if (num == 4) {
printf("죽음의 숫자 4 인가요 ;;; \n");
} else {
printf("그냥 평범한 숫자 %d \n", num);
}
먼저 if 문 안에 조건이 7인지 확인한다. 그런데 만약에 num
이 7이 아니라면 넘어가게 되는데 이때 넘어가는 곳이 바로 다음에 있는 else if
이다. else if
는 영어 뜻에서도 알 수 있듯이 "아닐경우 만약 ~ 이라면"이라는 뜻이다. 즉, 위 프로그램에 대해서 설명해보자면 7인지 확인하고 아닐경우 만약 4이면 "죽음의 숫자 4 인가요 ;;; " 를 출력하고 그마져도 아니면 "그냥 평범한 숫자 %d" 를 출력하라는 의미이다.
#include <stdio.h>
int main() {
int num;
printf("아무 숫자나 입력해 보세요 : ");
scanf("%d", &num);
if (num == 7) {
printf("a 행운의 숫자 7 이군요!\n");
} else if (num == 7) {
printf("b 행운의 숫자 7 이군요! \n");
}
return 0;
}
그렇다면 위처럼 작성하면 어떻게 될까? 만약 num
이 7일 경우 "a 행운의 숫자 7 이군요!" 가 실행되고 else if
구문 조건도 만족하여 "b 행운의 숫자 7 이군요!" 도 실행될 것 같지만 사실 그렇지 않다.
왜냐하면 앞서 누누이 말했듯이 else
문은 전제조건이 앞에 if
구문이 거짓일 경우 실행이 된다는 것이다.
즉 만약에 앞에 if
구문이 참일 경우 if
구문의 중괄호가 실행이 되고 if
문은 끝나게 된다. 즉 "a 행운의 숫자 7 이군요!" 만 출력하고 if
구문이 끝나고 return 0
로 넘어가게 된다.
if (num == 7) {
printf("c 행운의 숫자 7 이군요!\n");
}
if (num == 7) {
printf("d 행운의 숫자 7 이군요! \n");
}
그렇다면 위의 경우 num
이 7이면 어떻게 될까? 정답은 둘다 출력이 된다.
왜냐하면 둘 if
문은 서로 독립되어 있기 때문이다. 첫번째 if
문에 조건에 만족하여 구문 안에 중괄호를 실행하고 if
문이 끝나게 되고 그 다음으로 두번째 if
문이 실행이되고 똑같이 조건에 만족하여 중괄호가 실행이 된다.
만약에 조건이 10이상이고 20미만인 경우는 어떻게 프로그램을 만들어야 할까?
if (a >= 10) {
if (a < 20) {
printf(" %d 는 10 이상, 20 미만인 수 입니다. \n", a);
}
}
우리가 지금까지 알아보았던 방법으로는 위처럼 만들 수 있을 것이다. 그러나 이를 더 간단하게 표현할 수 있다.
여기서 사용하는 개념이 바로 논리 곱(AND) 이라고 불리는 논리 연산자이다.
/* 논리 연산자 */
#include <stdio.h>
int main() {
int a;
printf("아무 숫자나 입력하세요 : ");
scanf("%d", &a);
if (a >= 10 && a < 20) {
printf(" %d 는 10 이상, 20 미만인 수 입니다. \n", a);
}
return 0;
}
우리는 앞서 AND 연산에 대해서 배운적이 있다. AND 연산은 둘다 참일 경우에만 참(1)을 나타낸다. 둘중의 하나라도 조건에 맞지 않는 경우에는 거짓(0)을 나타낸다.
우리는 10 이상 20 미만, 즉 a >= 10
이면서(AND) a < 20
인 조건이 필요하기 때문에 AND연산을 사용하여 위처럼 사용하면 된다.
정리하자면 &&
는 두 조건이 참 일 경우에 if 구문 안에 중괄호가 실행되는 것이다.
그런데 왜 우리가 여태까지 알고 있었던 AND연산인 &를 사용하지 않고 &&를 사용할까?
이유는 & 한개는 말 그대로 비트 사이의 AND연산에 사용하는 것이고, 조건식 사이의 관계로 사용할 때는 &&를 사용해야 하는 것이다.
int main() {
int a = 31, // 1111
int b = 15; // 0111
printf("a & b = %d\n", a & b); // 0111
printf("a && b = %d\n", a && b);
}
a & b = 15
a && b = 1
위 예제를 보면 알 수 있다. &가 한개면 비트 연산 AND를 실행하여 0111
인 15가 나오는 것을 볼 수 있다.
&& 는 논리 곱 AND로 참(1) 과 거짓(0) 둘중 하나면 출력하게 된다.
그렇다면 반대로 && 대신 &를 쓰면 안될까? 왜냐하면 0이 아닌 값들은 어차피 참으로 간주되기 때문이다.(위의 예제에서도 a와 b 둘다 0이 아니기 때문에 둘다 참으로 간주되어 참(1) 이 출력이 된 것이다.)
둘다 0000 경우 즉 둘다 거짓인 경우에 0을 출력하기 때문에 사용해도 큰 문제가 없을 것 같다. 그런데 왜 &&를 사용하는게 좋을까?
if (height >= 180 && weight >= 90) {
}
예를 들어서 위의 조건을 한 번 확인해보자. 만약 height 이 179라고 해보자
그렇다면 앞서 이미 height >= 180
조건에 맞지 않기 때문에 뒤에 조건은 확인할 필요도 없이 거짓이다.
따라서 굳이 weight >= 90
을 확인해볼 필요가 없다.
위 경우 처럼 한 조건식을 확인했을 때 이미 전체 결과가 정해져 있는 경우에 굳이 다음 조건을 확인해볼 필요가 없는데 이 같은 경우 컴퓨터는 뒤에 조건식을 확인하지 않는다. 이러한 방식을 Short Circuit Evaluation 라 한다.
(줄여서 ****SCE라고 하자)
그런데 만약에 && 대신 &를 사용했다면 어떨까?
앞서 조건이 맞지 않아도 SCE를 사용할 수 없다 왜냐하면 &는 정확한 연산의 결과를 알기 위해서 뒤에 식도 계산해야 하기 때문이다. 하지만 &&의 경우 결과가 0인지 1인지만 알면 되니까 SCE를 사용할 수 있는 것이다.
#include <stdio.h>
int main() {
int height, weight;
printf("당신의 키와 몸무게를 각각 입력해 주세요 : ");
scanf("%d %d", &height, &weight);
if (height >= 190 || weight >= 100) {
printf("당신은 '거구' 입니다. \n");
}
return 0;
}
앞서 AND는 &&
사용했듯이 OR 에서는 ||
를 사용한다.
OR는 둘중의 하나라도 참이면 참을 나타낸다. 따라서 위의 프로그램은 키가 190 이상이거나 몸무게가 100이상면
'거구'라고 말한다.
#include <stdio.h>
int main() {
int height, weight;
printf("당신의 키와 몸무게를 각각 입력해 주세요 : ");
scanf("%d %d", &height, &weight);
if (height >= 190 || weight >= 100) {
printf("당신은 '거구' 입니다. \n");
}
if (!(height >= 190 || weight >= 100)) {
printf("당신은 거구가 아닙니다. \n");
}
return 0;
}
그렇다면 위의 프로그램에 height 가 180 이고 weight 이 80 인 값을 넣으면 어떻게 될까?
당신의 키와 몸무게를 각각 입력해 주세요 : 180 80
당신은 거구가 아닙니다.
거구가 아니라고 나온다.
if (!(height >= 190 || weight >= 100)) {
printf("당신은 거구가 아닙니다. \n");
}
를 자세히 보면 앞에 !
가 있다. 이 것은 NOT을 취해주는 연산자이다. 다시말해서 참을 거짓으로, 거짓을 참으로 나타낸다.
따라서 height >= 190 || weight >= 100
는 !
를 앞에 붙임으로서 height < 190 && weight < 100
과 똑같은 조건이 된다.
참고로 !
는 0이 아닌 값은 0으로 변환해준다는 특성을 사용하여 어떠한 값이 0인지 아닌지 판단하기 위해서 아래와 같이 사용한다.
if (!p) { // p == 0 과 같은 의미이지만 더 짧기 때문에 자주 사용된다 :)
// p 가 0 일 때에만 실행된다.
}