Notice
Recent Posts
Recent Comments
Link
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
관리 메뉴

문타쿠, 공부하다.

[독하게 시작하는 C 프로그래밍] 섹션 10. 연산자 본문

C언어/독하게 시작하는 C 프로그래밍

[독하게 시작하는 C 프로그래밍] 섹션 10. 연산자

개발새발 문타쿠 2023. 10. 29. 21:23

연산자 기본 이론

연산자

  • 연산자는 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;
}