목차
- 산술 연산자
- 증감 연산자
- 관계(비교) 연산자
- 논리 연산자
1. 산술 연산자
연산자는 보통 기능으로 분류하지만, 필요한 연산자(피연산자)의 개수로도 나눌 수 있습니다.
단항연산자, 이항연산자, 삼항연산자 등...
일단, 가장 만만한 산술 연산자부터 알아보죠.
산술 연산자는 수학에서도 많이 사용하는 사칙연산, 그리고 나머지를 의미합니다.
연산자 | 의미 |
+ | 더하기 |
- | 빼기(단항일 경우 부호 변환) |
* | 곱하기 |
/ | 나누기(정수연산과 실수연산 다름) |
% | 나머지 |
대충 이런 종류가 있어요.
그럼 바로 테스트..
#include <stdio.h>
int main()
{
int a = 30; //변수 선언과 동시에 초기화(대입)
int b = 10;
float c = 3.0;
int sum = 0;
int sub = 0;
int mul = 0;
int inv = 0;
float div = 0.0;
float rem = 0.0;
sum = a + b; //더하기 연산 후 대입 연산
sub = a - b; //빼기 연산 후 대입 연산
mul = a * b; //곱셈 연산 후 대입 연산
inv = -a; //음수 연산 후 대입 연산
div = b / c; //정수와 실수의 나누기 연산
rem = a % b; //정수와 정수의 나머지 연산
printf("합 : %d\n", sum);
printf("차 : %d\n", sub);
printf("곱 : %d\n", mul);
printf("부호변환 : %d\n", inv);
printf("나누기 : %f\n", div);
printf("나머지 : %d\n", rem);
return 0;
}
좋아요, 결과로는
합 : 40
차 : 20
곱 : 300
부호변환 : -30
나누기 : 3.333333
나머지 : 0
정도가 나오네요.
여담으로, 나누기 연산자 (/)는 두 항 중 하나라도 실수가 있으면 실수로 반환하고, 둘 다 정수라면 몫만 연산해요.
2. 증감 연산자
증감 연산자는 변수의 앞뒤에 ++ 혹은 --을 붙여서 사용해요.
의미는 그 변수에 1을 더하거나 빼는 것이고, 앞에 붙이면 전위 표기(prefix), 뒤에 붙이면 후위 표기(postfix)라고 해요.
당연하게도 상수에는 사용할수없고.. 한번 활용해보죠.
#include <stdio.h>
int main()
{
int a = 10;
int b = 0;
printf("%d\n", a);
b = ++a;
printf("%d %d\n", a, b); //전위형 증감 연산 사용
b = 0;
--a;
b = a++;
printf("%d %d\n", a, b); //후위형 증감 연산 사용
return 0;
}
자, 결과가 어떨까요?
10
11 11
11 10
흠, 왜 이런지 아시나요?
이유는 간단해요, 전위 연산은 해당하는 변수를 먼저 바꾼 다음 연산을 수행하지만
후위 연산은 연산을 모두 끝내고 해당하는 변수를 바꾸거든요.
3. 관계(비교) 연산자
관계 연산자는 다음과 같아요.
연산식 | 의미 | 결과 |
a > b | a가 b보다 큰가? | a가 b보다 크다면 1, 그렇지 않으면 0 |
a >= b | a가 b보다 크거나 같은가? | a가 b보다 크거나 같다면 1, 그렇지 않으면 0 |
a < b | a가 b보다 작은가? | a가 b보다 작다면 1, 그렇지 않으면 0 |
a <= b | a가 b보다 작거나 같은가? | a가 b보다 작거나 같다면 1, 그렇지 않으면 0 |
a == b | a와 b가 같은가? | a가 b와 같으면 1, 그렇지 않으면 0 |
a != b | a와 b가 다른가? | a가 b와 다르면 1, 그렇지 않으면 0 |
여담으로, 사실 참(True)는 0을 제외한 모든 값이 해당되고, 거짓(False)는 0만 해당된답니다.
한번 실습해볼까요..
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int res = 0;
res = a > b; // a > b 는 거짓이므로 결과값은 0
printf("a > b = %d\n", res);
res = a >= b; // a >= b 는 거짓이므로 결과값은 0
printf("a >= b = %d\n", res);
res = a < b; // a < b 는 참이므로 결과값은 1
printf("a < b = %d\n", res);
res = a <= b; // a <= b 는 참이므로 결과값은 1
printf("a <= b = %d\n", res);
res = a == b; // a == b 는 거짓이므로 결과값은 0
printf("a == b = %d\n", res);
res = a != b; // a ! b 는 참이므로 결과값은 1
printf("a != b = %d\n", res);
return 0;
}
좋아요, 결과를 보면
a > b = 0
a >= b = 0
a < b = 1
a <= b = 1
a == b = 0
a != b = 1
원하는대로 나오네요.
그리고 C의 모든 연산자는 동치(=)가 나중에 들어가는 것을 기억하세요.
그리고.. 음, 10 < a < 20을 하면 값은 어떨 때 참이 나올까요?
a가 11, 12.. 18, 19 일 때 참이라고 생각되지만, 실제로는 달라요. a에 40을 대입해보죠.
10 < a(40) < 20
왼쪽 연산자가 먼저 처리되고, 값은 1이 되고..
1 < 20 이므로 저 식은 실제로는 a > 10 일 때 참이 되요.
이런 문제를 방지하기 위해서 논리 연산자를 사용하죠.
4. 논리 연산자
논리 연산자는 참과 거짓을 가지고 연산해요, 다행인점은 숫자가 적다는 것.
연산식 | 논리관계 | 결과값 |
a && b | 논리곱(AND) | a와 b 모두 참이면 참 |
a || b | 논리합(OR) | a와 b 중 하나가 참이면 참 |
!a | 논리부정(NOT) | a가 참이면 거짓, 거짓이면 참 |
여담으로 논리합의 || 은 백슬래시(\)의 쉬프트에요.
그럼, 당장 써보죠.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int res = 0;
res = (a == 10) && (b == 10); //좌항과 우항이 모두 참이면 참
printf("(a == 10) && (b == 10) = %d", res);
return 0;
}
결과는?
(a == 10) && (b == 10) = 0
이에요, 좌항은 참이지만 우항이 거짓이라 틀렸어요.
좌항(참 또는 거짓) | 우항(참 또는 거짓) | && 결과(AND) |
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
|| 결과(OR) | ||
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
! 결과(NOT) | ||
1 | 0 | |
0 | 1 |
여담으로 연산은 이래요.
그리고 주의해야 할 점이 있는데, C의 논리 연산자는 숏 서킷 룰(short circuit rule)가 적용되요.
이게 뭐냐면 좌항만 연산해서 식의 참거짓을 판별하는건데..
예를 들어 && 연산자는 좌항이 거짓이면 우항이 뭐든 결과를 거짓으로 바꾸고,
|| 연산자는 좌항이 참이면 우항이 뭐든 결과를 참으로 바꿔요.
여기서 중요한 점은, 그냥 우항이 실행되지 않는다는거에요.
가령 ++b같은 증감연산자가 말이죠. 그러니 주의하도록 합시다.