관리 메뉴

클라이언트/ 서버/ 엔지니어 "게임 개발자"를 향한 매일의 공부일지

연산자 1 - 산술 · 관계 · 논리 연산자 본문

프로그래밍 언어/C 언어

연산자 1 - 산술 · 관계 · 논리 연산자

huenuri 2024. 7. 30. 05:08

오늘 학습할 부분은 연산자이다. 연산자는 응용문제로 코딩테스트 문제를 풀고 정리해보았으나, 개념 학습은 아직 하지 않아서 오늘은 이 분분을 학습해보기로 했다.

프로그램은 연산을 통해 데이터를 처리하므로 다양한 연산자의 사용법을 익히는 일은 매우 중요하다. 먼저 기본적인 산술 연산자, 제어문의 조건식에 주로 사용되는 관계 연산자 및 논리 연산자에 관해 살펴볼 것이다.

 

시작하기 전에

프로그램은 CPU가 처리하는 명령어의 묶음이다. 일반적으로 연산자는 컴파일되면 명령어로 부뀌므로 연산자를 배우는 것은 결국 명령어를 익히는 것이다. 연산 명령에는 연산의 대상이 되는 데이터가 필요한데 이를 피연산자라고 한다.

 


 

 

1. 산술 연산자와 대입 연산자

 

산술 연산자

연산자는 연산 기호이고, 피연산자는 연산의 대상이 되는 데이터이다.

산술연산자에는 +, -, *, /, % 가 있다. 모두 2개의 피연산자를 사용하며 이중 빼기 연산자는 피연산자를 하나면 사용할 때 피연산자의 부호를 바꾸는 역할도 한다.

 

🐺 대입, 더하기, 빼기, 곱하기, 음수 연산

#include <stdio.h> int main(void) { int a, b; int sum, sub, mul, inv; a = 10; b = 20; sum = a + b; sub = a - b; mul = a * b; inv = -a; printf("a의 값 : %d, b의 값 : %d\n", a, b); printf("덧셈 : %d\n", sum); printf("뺄셈 : %d\n", sub); printf("곱셈 : %d\n", mul); printf("a의 음수 연산 : %d\n", inv); return 0; }

 

 

대입 연산자

 

오른쪽 수식의 결과를 왼쪽 변수에 저장한다. 여기서 수식은 상수나 변수 또는 연산자를 사용한 식을 모두 포함한다.

 

대입 연산자를 다른 연산자와 함께 사용할 때는 우선순위에 따라 다른 연산을 먼저 수행하고 그 결과를 왼쪽 변수에 저장한다.

 

나누기 연산자와 나머지 연산자

 

나누기 연산자를 사용할 때는 피연산자의 형태에 따라 결과가 달라지니 주의해야 한다. 정수로 연산할 때는 몫을 구하고 실수로 연산할 때는 소수점까지 구한다.

 

🐺 몫과 나머지를 구하는 연산

  • 실수 연산에는 나머지의 개념이 억으므로 나머지 연산자의 피연산자로는 반드시 정수만을 사용
#include <stdio.h> 
int main(void) 
{ 
  double apple; 
  int banana; 
  int orange; 
  apple = 5.0 / 2.0; banana = 5 / 2; 
  orange = 5 % 2; 
  
  printf("apple : %.1lf\n", apple); 
  printf("banana : %d\n", banana); 
  printf("orange : %d\n", orange); 
  return 0; 
}

나눗셈 연산은 결과값이 정수 또는 실수가 될 수 있으므로 그 값을 저장하는 변수도 그에 맞게 사용해야 한다.

몫을 뺀 나머지만 구할 때는 나머지 연산자인 %를 사용한다. 실수 연산에는 나머지의 개념이 없으므로 나머지 연산자의 피연산자로는 반드시 정수만을 사용한다.

 

 

 

2. 증감 연산자

 

 

증감 연산자는 하나의 연산자라 대입 연산까지 수행하므로 변수의 값을 1씩 증가시키거나 감소시킬 때 사용할 수 있다.

 

 

🐺 증가 연산자의 연산

#include <stdio.h> 
int main(void) 
{ 
  int a = 10, b = 20; 
  ++a; --b; 
  printf("a : %d\n", a); 
  printf("b : %d\n", b); 
  return 0; 
 }

전위 표시와 후위 표시

전위 표기는 증감 연산자가 피연산자 앞에 놓이는 것이고, 후위 표기는 뒤에 놓이는 것이다.

전위 표기는 값이 증감하고 나서 연산에 사용하고, 후위 표기는 연산에 사용하고 나서 값이 증감한다.

 

🐺 전위 표기와 후위 표기를 사용한 증감 연산

#include <stdio.h> 
int main(void) 
{ 
  int a = 5, b = 7; 
  int pre, post; 
  pre = (++a) * 3; 
  post = (b++) * 3; 
  
  printf("증감 연산 후 초깃값 a = %d, b = %d\n", a, b); 
  printf("전위형 : (++a) * 3 = %d, 후위형 : (b++) * 3 = %d\n", pre, post); 
  return 0; 
 }
 

 

후위 표기는 다른 연산자와 함께 사용될 때 가장 나중에 연산된다고 생각하면 된다.


 

 

 

3. 관계 연산자

 

조건에 따라 명령을 실행해야 하는 경우가 있는데 이때 특정한 기준, 조건에 관해 명령을 실행하려면 관계 연산자가 필요하다.

관계 연산자에는 대소 관계 연산자와 동등 관계 연산자가 있다.

 

 

이들 연산자는 모두 피연산자를 2개 사용하며, 연산의 결과값은 1또는 0이다. 컴파일러는 참과 거짓을 1과 0으로 판단하므로 관계식을 실행 조건 검사에 사용할 수 있다.

 

 

🐺 관계 연산의 결과값 확인

#include <stdio.h> 
int main(void) 
{ 
  int a = 10, b = 20, c = 10; 
  int res; res = (a > b); 
  printf("a > b : %d\n", res); 
  res = (a >= b); 
  printf("a >= b : %d\n", res); 
  res = (a < b); 
  printf("a < b : %d\n", res); 
  res = (a <= b); 
  printf("a <= b : %d\n", res); 
  res = (a <= c); 
  printf("a <= c : %d\n", res); 
  res = (a == b); 
  printf("a == b : %d\n", res); 
  res = (a != c); 
  printf("a != c : %d\n", res); 
  return 0; 
 }
 

 

 

🤠 a = 5와 a == 5의 차이점

= : 대입 연산자, == : 같다


 

 

 

 

4. 논리 연산자

 

논리 관계를 판단하는데 사용된다.

 

 

🐺 논리 연산의 결과값 확인

#include <stdio.h> 
int main(void) 
{ 
  int a = 30; 
  int res; 
  res = (a > 10) && (a < 20); 
  printf("(a > 10) && (a < 20) : %d\n", res); 
  res = (a < 10) || (a > 20); 
  printf("(a < 10) || (a > 20) : %d\n", res); 
  res = !(a >= 30); 
  printf("!(a >= 30) : %d\n", res); 
  return 0; 
 }
 

 

관계 연산자만을 사용할 때

10 < a < 20 -> 참

 

논리 연산자를 함께 사용할 때

(10 < a) && (a < 20) -> 거짓

 

숏 서킷 룰

좌항만으로 &&와 || 연산 결과를 판별하는 기능이다. 예를 들어 &&는 좌함이 거짓이면 우항과 관계없이 결과는 거짓이므로 우항을 살펴볼 필요가 없다.

또한 ||는 좌항이 참이면 우항과 관계없이 결과가 참이다.

(a < 0) && (++b > 20)

 

이 식에서 항상 ++b가 실행되길 기대할 수 없다. 왜냐하면 a가 0보다 크면 b 값은 증가되지 않기 때문이다. 결국 숏 서킷 룰은 불필요한 연산을 줄여 실행 속도를 높일 수는 있으나 예상치 못한 결과를 만들 수 있다.

따라서 &&과 ||를 사용할 때는 숏 서킷 룰에 주의해야 한다.

 


 

 

 

5. 연산의 결과값을 처리하는 방법

 

연산을 실행한 후 연산의 결과값을 변수에 저장하지 않으면 그 값은 버져진다. 따라서 연산 결과를 곧바로 사용하거나 대입 연산을 통해 다른 변수에 저장해야 한다.

 

 

🐺 연산의 결과값을 사용하는 방법

 

CPU의 메모리와 우리가 알고 있는 메모리(RAM)은 어떻게 다른가?

CPU의 메모리를 레지스터라고 하며, 여기에 연산할 데이터와 연산 후의 결과를 임시 저장한다.

보통 레지스터는 CPU와 1:1 동기화되어 있어 메모리(RAM)에 비해 엄청나게 빠르다. 따라서 실행 속도만 생각한다면 메모리보다 레지스터를 사용하는 편이 훨씬 유리하다.

다만 레지스터는 다음 연산을 위해 계속 사용되므로 연산 결과를 메모리로 옮겨 놓지 않으면 그 값은 사라진다.

 


 

연습문제

 

문제 1

 

4.0과 1.2를 덧셈, 뺄셈, 곱셈, 나눗셈한 값을 소숫점 이하 첫째 자리까지 출력하라.

#include <stdio.h> 
int main(void) 
{ 
  double a = 4.0, b = 1.2; 
  printf("%.1lf + %.1lf = %.1lf\n", a, b, a + b); 
  printf("%.1lf - %.1lf = %.1lf\n", a, b, a - b); 
  printf("%.1lf * %.1lf = %.1lf\n", a, b, a * b); 
  printf("%.1lf / %.1lf = %.1lf\n", a, b, a / b); 
  return 0; 
 }
 

 

문제 2

 

두 과목의 점수를 입력해 평균을 출력하는 프로그램을 완성하라.

#include <stdio.h> 
int main(void) 
{ 
  int a, b, tot; 
  double avg; 
  printf("두 과목의 점수 : "); 
  scanf_s("%d%d", &a, &b); 
  tot = a + b; 
  avg = tot / 2.0; 
  printf("평균 : %.1lf\n", avg); 
  return 0; 
 }
 
 

 

문제 3

 

전체 학점과 평점을 계산해 신청 학점이 10학점 이상이고 평점 평균이 4.0을 넘는 경우 1을 출력하고, 그렇지 않으면 0을 출력하는 프로그램 작성하시오.

국어 - 3학점 - 3.8

영어 - 5학점 - 4.4

수학 - 4학점 - 3.9

#include <stdio.h> 
int main(void) 
{ 
  int kor = 3, eng = 5, mat = 4; 
  int credits; 
  int res; 
  double kscore = 3.8, escore = 4.4, mscore = 3.9; 
  double grade; 
  credits = kor + eng + mat; 
  grade = (kscore + escore + mscore) / 3.0; 
  res = (credits >= 10) && (grade > 4.0); 
  printf("%d", res); return 0; 
 }

이 문제는 조금 어려운 문제처럼 보이지만, 변수만 제대로 사용하면 충분히 풀수 있는 문제이다. 학점은 실수이므로 double로 받았다. 학점, 연산결과, 평점 등을 저장할 변수를 담고, 값이 주어지는 경우에는 해당 값으로 초기화를 시켜준다.

결과는 참이므로 1이 출력되었다.


 

 

 

오늘의 학습을 마치고

 

학원에서 PPT 문서가 없어서 그걸 어떻게 볼 수 있는지 찾아보다가 30분이 훌쩍 지났다. 시간이 많이 아까웠지만 할 수 없었다.

그래도 다음에는 이 부분이 해결되었으니 더는 지체할 일이 없을 것 같다.

집에서 할 때는 솔직히 훨씬 더 집중도 잘되고 공부도 잘 되는 것 같다. 학원에서는 수업 시간에 헤드폰을 끼고 강의 소리가 들리지 않게 음악을 들으면서 하기에 집중은 좀 떨어진다. 그렇다고 집에서 열심히 공부하는 건 아니니 이 부분은 어쩔 수 없는 일이다.

 

이미 다 알고 있는 내용이지만 다시 한번 마지막으로 정리한다고 생각하고 책에 있는 내용을 빠짐없이 필기해보았다.

증감 연산자에서 값이 변하는 부분이 조금 헤깔리는 했으나 새로운 것들도 알게 되었다. 관계연산자만 혹은 논리연산자만 사용할 때 참과 거짓이 바뀌게 된다는 이상한 현상을 배울 수 있었다.

그리고 &&와 ||을 사용할 때는 숏 서킷 룰에 주의해야 한다는 것도 꼭 기억해야겠다.