문타쿠, 공부하다.
[독하게 시작하는 C 프로그래밍] 섹션 10. 연산자 본문
연산자 기본 이론
연산자
- 연산자는 CPU 연산과 직결되는 문법
- 연산자 자체는 하나의 항
- 여러 항을 모아 연산식 작성
- 연산자와 피연산자로 구성
- 피연산자가 하나면 단항 연산자, 두 개 항이면 이항 연산자, 세 개 항이면 삼항 연산자
연산자 종류
- 산술 연산자
- 대입 연산자
- 형 변환 연산자
- 단항 증/감 연산자
- 비트 연산자
- 관계 연산자, 논리 연산자, 조건 연산자
- sizeof 연산자
연산자 우선 순위
연산자 결합성
- 우선순위가 같은 경우 어떤 것을 먼저 연산할 것인지 나타내는 것
산술 연산자
- 대표적인 이항 연산자: +, -, *, /, %
- 연산의 결과로 임시결과 발생
- 정수 간 나눗셈의 결과는 반드시 정수가 되며 소수점 이하는 절사
이형자료 연산과 형승격
산술 연산과 형승격
- 임시결과는 피연산자 표현범위 이상의 표현이 가능해야 함
- char + int 결과는 int
- double * int 결과는 double
- 4 / 3 (int / int = int)과 4.0 / 3 (double / int = double)은 전혀 다른 연산
0으로 나누면 안 되는 이유
#include <stdio.h>
int main(void)
{
int input = 0;
printf("정수 입력 ㄱㄱ: ");
scanf_s("%d", &input);
printf("10 / %d = %d\n", input, 10 / input);
return 0;
}
프로그램에서 어떤 수를 0으로 나눌 수 없는데(섹션 4 참고), 만약 위의 코드에서 사용자가 0을 입력하게 된다면 프로그램은 고대로 죽어버림 => 코드를 짤 때 유저를 절대 믿지 말라.!
[필수 실습 문제] 평균 값 구하기
#include <stdio.h>
int main(void)
{
int num1 = 0;
int num2 = 0;
double avg = 0.0;
printf("정수 두 개를 입력하세용\n");
printf("첫 번째 정수: ");
scanf_s("%d", &num1);
printf("두 번째 정수: ");
scanf_s("%d", &num2);
avg = (num1 + num2) / 2.0;
printf("%d과(와) %d의 평균은 %.2f입니다.\n", num1, num2, avg);
return 0;
}
[필수 실습 문제] 시 분 초 계산하기
#include <stdio.h>
int main(void)
{
int num1 = 0;
int hour = 0, minute = 0, second = 0;
printf("정수 하나 입력 기릿: ");
scanf_s("%d", &num1);
hour = (num1 / 60) / 60;
minute = (num1 / 60) % 60;
second = num1 % 60;
printf("%d초는 %02d시간 %02d분 %02d초입니다.\n", num1, hour, minute, second);
return 0;
}
단순 대입 연산자
- 두 피연산자 중 오른쪽 피연산자(R-value)의 값을 왼쪽 피연산자(L-value)에 저장하는 연산자
- L-value는 Overwrite가 발생하며 기존 값이 사라짐
- 상수는 L-value가 될 수 없음
[필수 실습 문제] 두 변수 값 교환
#include <stdio.h>
int main(void)
{
int num1 = 0, num2 = 0;
int tmp = 0;
printf("두 개의 정수 입력 ㄱㄱ\n");
printf(">> ");
scanf_s("%d", &num1);
printf(">> ");
scanf_s("%d", &num2);
printf("\n자리 바꾸기 전\n");
printf("num1: %d, num2: %d\n", num1, num2);
tmp = num1;
num1 = num2;
num2 = tmp;
printf("\n자리 바꾸기\n");
printf("num1: %d, num2: %d", num1, num2);
return 0;
}
복합 대입 연산자
- 기능상 단순 대입 연산자와 산술 연산자 그리고 비트 연산자가 조합된 연산자
- 누적 연산 시 += 연산자 활용
[필수 실습 문제] 세 정수 총 합 계산하기 (누산)
#include <stdio.h>
int main(void)
{
int input = 0;
int sum = 0;
printf("세 개의 정수 입력 ㄱㄱ\n");
printf(">> ");
scanf_s("%d", &input);
sum += input;
printf(">> ");
scanf_s("%d", &input);
sum += input;
printf(">> ");
scanf_s("%d", &input);
sum += input;
printf("합계: %d", sum);
return 0;
}
형 변환 연산자
- 피연산자의 형식을 강제로 변경해주는 단항 연산자
- 부적절한 변환 시 정보가 유실될 수 있음
단항 증/감 연산자
- 피연산자에 저장된 값을 1씩 증가시키거나 감소시키는 연산
- 피연산자는 반드시 쓰기가 가능한 L-value여야 함
- 전위식, 후위식 표기가 가능하며 후위식이 될 경우 연산자 우선순위가 전체 식을 평가한 후로 미뤄짐
비트 연산자와 엔디안(Endian)
비트 연산자
- 자료를 비트 단위로 논리 식을 수행하는 연산
- 보통 2진수로 변환해 판단
- AND(&), OR(|), NOT(~), XOR(^), Shift left(<<, 곱셈), Shift right(>>, 나눗셈)
- NOT은 단항, 모두 이항 연산자
비트 마스크 연산
- 데이터에서 특정 영역의 값이 모두 0이 되도록 지우는 연산
- AND의 특징을 이용
- 0과 AND 연산을 수행하면 결과는 무조건 0
엔디안(Endian)
- 컴퓨터 메모리 내에서 다중 바이트 데이터의 바이트 순서를 나타내는 방식
- 빅 엔디안 (Big Endian)
- 0x12345678이라는 4바이트 정수가 있다면 메모리에 저장될 때 MSB(최상위 바이트, Most Significant Byte)인 0x12가 가장 낮은 주소에, LSB(최하위 바이트, Least Significant Byte)인 0x78이 가장 높은 주소에 저장
- 리틀 엔디안 (Little Endian)
- 0x12345678은 리틀 엔디안 시스템에서 0x78이 가장 낮은 주소에, 0x12가 가장 높은 주소에 저장
[필수 실습 문제] 뺄셈 연산 직접 구현하기
#include <stdio.h>
int main(void)
{
int num1 = 0, num2 = 0;
int result = 0;
printf("두 개의 정수 입력 ㄱㄱ\n");
printf(">> ");
scanf_s("%d", &num1);
printf(">> ");
scanf_s("%d", &num2);
// (num2의 1의 보수 + 1) = num2의 2의 보수
result = (~num2 + 1) + num1;
printf("결과: %d", result);
return 0;
}
sizeof 연산자 (그리고 _countof( ) )
- 피연산자의 자료형에 대해 수행하는 컴파일 타임 연산자
- sizeof(10)과 sizeof(int)의 결과는 4로 같음
- 배열에 대해서도 적용 가능
- 최대한 자주 사용할 것!
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int array[16];
// sizeof(): 배열의 크기를 나타냄
// 4바이트(int) * 16개 = 64바이트
printf("%lld\n", sizeof(array));
// _countof(): 배열 요소의 개수를 나타냄
// stdlib.h 헤더파일 필요
printf("%lld\n", _countof(array));
return 0;
}
관계 연산자
- 두 피연산자의 값을 비교(뺄셈)해 결과 도출
- 상등, 부등, 관계 연산자로 분류
- 상등(==), 부등(!=) 연산은 좌항에서 우항을 뺀 결과를 비교하는 관계 연산
- 실수형에 대해 상등, 부등 연산은 절.대.로 불가능
- 비교 연산: >, <, >=, <=
논리 연산자
- 항 혹은 연산식을 피연산자로 두는 논리합(OR, ||), 논리곱(AND, &&) 이항 연산자
- 논리 부정(NOT, !) 연산자는 단항 연산자
- 값의 범위 표현 시 사용되는 것이 보통
- 결합성이 L -> R이므로 왼쪽에 등장하는 연산식을 우선 평가하고 이어지는 연산식을 수행할 것인지 판단
- 0은 거짓, 음수 포함 0이 아닌 모든 수는 참
쇼트 서킷과 범위검사 흔한 오류 예
Short Circuit
- 논리 식은 왼쪽부터 실행
- 피연산자 항이 식일 경우 식부터 평가
- 논리합의 경우 왼쪽 조건이 만족되면 이후 식은 연산하지 않음
- 논리곱의 경우 마지막 식까지 모두 평가해 모든 결과가 참인지 확인
조건 (삼항) 연산자
- C언어의 유일한 삼항 연산자
- (조건식) ? (항A) : (항B)
- 논리적 오류를 피하려면 선택 대상 항은 괄호로 묶어 표기
[필수 실습 문제] 합격, 불합격 판단하기
#include <stdio.h>
int main(void)
{
int score = 0;
printf("점수(0~100)를 입력하세요: ");
scanf_s("%d", &score);
printf("%s\n", (score >= 80) ? "합격" : "불합격");
return 0;
}
[필수 실습 문제] 최댓값 구하기 - 서바이벌 방식
#include <stdio.h>
int main(void)
{
int input = 0;
int max = 0;
printf("정수를 입력하세요.\n");
printf(">> ");
scanf_s("%d", &input);
max = input;
printf(">> ");
scanf_s("%d", &input);
max = (input > max) ? input : max;
printf(">> ");
scanf_s("%d", &input);
max = (input > max) ? input : max;
printf("최댓값: %d\n", max);
return 0;
}
[필수 실습 문제] 최댓값 구하기 - 토너먼트 방식
#include <stdio.h>
int main(void)
{
int num1 = 0, num2 = 0, num3 = 0;
int max = 0;
printf("세 개의 정수를 입력하세요.\n");
printf(">> ");
scanf_s("%d%d%d", &num1, &num2, &num3);
max = (num1 > num2) ? num1 : num2;
max = (max > num3) ? max : num3;
printf("최댓값: %d\n", max);
return 0;
}
'C언어 > 독하게 시작하는 C 프로그래밍' 카테고리의 다른 글
[독하게 시작하는 C 프로그래밍] 섹션 12. 반복문 (0) | 2023.11.02 |
---|---|
[독하게 시작하는 C 프로그래밍] 섹션 11. 기본 제어문 (0) | 2023.11.01 |
[독하게 시작하는 C 프로그래밍] 섹션 9. 표준 입/출력 (0) | 2023.10.28 |
[독하게 시작하는 C 프로그래밍] 섹션 8. C언어 기초 문법 (0) | 2023.10.24 |
[독하게 시작하는 C 프로그래밍] 섹션 7. 개발환경 구축 (Part 2. C 프로그래밍의 시작) (0) | 2023.10.24 |