프로그램이 하는 일의 대부분은 결국 계산입니다. 물건값을 더하고, 방문자 수를 하나씩 늘리고, 사탕을 사람 수대로 나누는 일이 모두 계산이지요. 이런 계산을 시키는 기호가 연산자입니다. 이번 편에서는 숫자를 더하고 빼고 곱하고 나누는 산술 연산자, 계산한 값을 변수에 담는 대입 연산자, 값을 하나씩 늘리고 줄이는 증감 연산자를 다룹니다. 짧은 예제를 직접 따라 치고 실행하며 읽기를 권합니다.
05.1 더하고 빼고 곱하고 나누는 산술 연산자
산술 연산자는 초등학교 때 배운 사칙연산에 나머지 하나를 더한 다섯 가지입니다. 더하기 +, 빼기 -, 곱하기 *, 나누기 /, 그리고 나눗셈의 나머지를 구하는 %입니다. 곱하기가 별표 *, 나누기가 빗금 /인 점만 익히면 됩니다. 변수 두 개로 실제 계산해 보겠습니다.
#include <stdio.h>
int main(void) {
int a = 7, b = 3;
printf("합 %d\n", a + b);
printf("차 %d\n", a - b);
printf("곱 %d\n", a * b);
printf("몫 %d\n", a / b);
printf("나머지 %d\n", a % b);
return 0;
}
실행하면 이렇게 나옵니다.
합 10
차 4
곱 21
몫 2
나머지 1
여기서 %d는 그 자리에 정수를 끼워 출력하라는 표시, \n은 줄바꿈 신호입니다. 더하기 빼기 곱하기는 예상대로인데, 나누기에서 7 / 3이 2로 나온 점이 이상해 보일 겁니다. 이 지점이 초보자가 가장 많이 걸려 넘어지는 곳입니다.
05.2 정수끼리 나누면 소수점이 사라지는 함정
함정. 정수끼리 나눗셈을 하면 소수점 아래가 반올림도 없이 그냥 버려집니다. 7 / 3은 수학에서 2.33이 넘지만 C에서는 몫인 2만 남습니다. 정수는 소수점을 담을 수 없는 자료형이라 정수끼리 나눈 결과도 정수로 맞추기 때문입니다. %는 이때 버려진 나머지를 알려 주는 연산자로, 7 / 3이 몫 2에 나머지 1이라는 뜻입니다.
int x = 5, y = 2;
printf("%d\n", x / y); // 2, 2.5가 아님
printf("%d\n", x % y); // 1
실행 결과.
2
1
소수점까지 제대로 된 답을 얻으려면 나누는 두 값 가운데 하나를 실수로 바꿔야 합니다. 소수를 담는 자료형인 double로 잠시 바꾸는 형변환 (double)을 앞에 붙이면 됩니다.
int x = 5, y = 2;
printf("%.1f\n", (double)x / y); // 2.5
실행 결과.
2.5
한쪽을 double로 바꾸면 나머지도 실수로 맞춰져 실수 나눗셈이 되고 소수점 아래가 살아납니다. %.1f는 소수점 첫째 자리까지 출력하라는 표시입니다.
05.3 나머지 연산자가 쓸모 있는 순간
나머지를 구하는 %는 무언가를 똑같이 나눠 담는 상황에서 자주 등장합니다. 사탕 17개를 다섯 명이 똑같이 나눠 가질 때, 한 명이 몇 개씩 갖고 몇 개가 남는지를 /와 % 한 쌍으로 바로 구할 수 있습니다.
int candy = 17, people = 5;
printf("한 명당 %d개\n", candy / people);
printf("남는 것 %d개\n", candy % people);
실행 결과.
한 명당 3개
남는 것 2개
어떤 수가 짝수인지 홀수인지 n % 2가 0인지로 가리는 데에도 쓰입니다.
05.4 계산한 값을 담는 대입 연산자
등호 =는 수학에서는 양쪽이 같다는 뜻이지만, C에서는 전혀 다릅니다. =는 오른쪽을 계산한 값을 왼쪽 변수에 넣어 두라는 명령입니다. 그래서 score = 100은 둘이 같다는 말이 아니라 score라는 상자에 100을 담으라는 뜻입니다. 이미 값이 들어 있던 변수에 대입하면 옛 값은 지워지고 새 값으로 덮어써집니다.
int score = 0;
printf("시작 %d\n", score);
score = 100; // 0을 지우고 100을 새로 담음
printf("현재 %d\n", score);
score = score + 50; // 오른쪽을 먼저 계산해 150을 담음
printf("보너스 %d\n", score);
실행 결과.
시작 0
현재 100
보너스 150
score = score + 50은 수학이라면 말이 안 되지만, =가 대입임을 알면 자연스럽습니다. 오른쪽 score + 50을 먼저 계산해 150을 만든 뒤 그 값을 다시 왼쪽 score에 담는 것입니다.
05.5 같은 변수에 더 얹는 복합 대입 연산자
방금처럼 기존 값에 얼마를 더해 다시 담는 일은 아주 자주 일어납니다. 그래서 C는 이를 짧게 줄여 쓰는 복합 대입 연산자를 마련해 두었습니다. score = score + 50은 score += 50으로 줄여 쓸 수 있고, 뜻은 완전히 같습니다. 빼기 곱하기 나누기 나머지에도 똑같이 -=, *=, /=, %=가 있습니다.
int cart = 10000;
cart += 3000; // 배송비, cart = cart + 3000 과 같음
printf("배송비 포함 %d\n", cart);
cart -= 2000; // 쿠폰 할인
printf("쿠폰 적용 %d\n", cart);
cart *= 2; // 두 세트 주문
printf("두 세트 %d\n", cart);
실행 결과.
배송비 포함 13000
쿠폰 적용 11000
두 세트 22000
왼쪽 변수를 두 번 쓰지 않아 짧고 읽기 쉬워, 하나의 값을 계속 갱신하는 코드에서 특히 즐겨 씁니다.
05.6 하나씩 늘리고 줄이는 증감 연산자
값을 딱 1만큼 늘리거나 줄이는 일은 어찌나 잦은지 여기에도 전용 기호가 따로 있습니다. ++는 1을 더하고 --는 1을 뺍니다. count++는 count += 1과, 곧 count = count + 1과 같은 뜻으로, 하나씩 세어 나가는 값에 잘 어울립니다.
int count = 0;
count++; // 1 증가
count++;
printf("방문자 %d명\n", count);
count--; // 1 감소
printf("한 명 나감 %d명\n", count);
실행 결과.
방문자 2명
한 명 나감 1명
05.7 전위와 후위, ++i 와 i++ 의 함정
![[C 05] 계산과 대입, 증감 연산자](https://img.thenullpage.com/posts/6540/6540_2_16f28a.webp)
증감 연산자는 변수 앞에 붙일 수도 있고 뒤에 붙일 수도 있습니다. 변수를 1 늘린다는 점은 똑같지만, 그 값을 다른 곳에 곧바로 쓸 때 함정.이 숨어 있습니다. 앞에 붙는 전위 ++i는 먼저 1을 늘린 뒤 그 늘어난 값을 내놓고, 뒤에 붙는 후위 i++는 늘리기 전의 옛 값을 먼저 내놓은 다음에 1을 늘립니다.
int i = 5;
printf("후위 %d\n", i++); // 옛 값 5를 먼저 내놓고
printf("증가 후 %d\n", i); // 그 뒤 i는 6
int j = 5;
printf("전위 %d\n", ++j); // 먼저 6으로 늘린 뒤 그 값을 내놓고
printf("증가 후 %d\n", j); // j도 6
실행 결과.
후위 5
증가 후 6
전위 6
증가 후 6
두 경우 모두 마지막에는 변수가 똑같이 6이 됩니다. 다른 것은 그 자리에서 내놓는 값이라, 후위 i++는 늘리기 전 값 5를, 전위 ++j는 늘린 뒤 값 6을 내놓습니다. 값만 늘리고 그 결과를 쓰지 않는 count++; 같은 단독 문장에서는 차이가 없지만, printf 안에 넣어 그 값을 바로 쓰는 순간 결과가 갈립니다.
주의. 한 문장 안에서 같은 변수를 증감하면서 동시에 다른 곳에도 쓰는 i = i++;나 a[i] = i++; 같은 코드는 결과가 컴파일러마다 달라지는 위험한 표현이니 절대 쓰지 않아야 합니다. 증감은 한 문장에서 한 번만, 단순하게 쓰는 것이 안전합니다.
연산자는 눈으로 읽기보다 직접 고쳐 돌려 보는 편이 빠르게 익습니다. 위 예제에서 7 / 3을 8 / 3으로, i++를 ++i로 바꿔 결과가 어떻게 달라지는지 확인해 보시기 바랍니다. 정수 나눗셈이 소수점을 버린다는 감각과 후위 증감이 옛 값을 먼저 내놓는다는 감각이 손에 붙으면 앞으로 만날 계산 코드가 한결 편안해집니다.