단락 평가(short-circuit evalution) : 첫 번째 값만으로 결과가 확실할 때 두 번째 값은 확인(평가) 하지 않는 방법 ex1) AND 연산자는 두 값이 모두 참이어야 참이 되므로 첫 번째 값이 거짓이면 뒤의 값은 확인하지 않고 바로 거짓으로 결정됨. ex2) OR 연산자는 두 값 중 하나만 참이면 참이 되므로 첫 번째 값이 참이면 뒤의 값은 확인하지 않고 바로 참으로 결정됨.
조건문
if문
if(조건식)
{
//조건식이 true일 때 수행될 문장
}
조건식을 만족하면 괄호 안의 문장들을 실행시킨다.
■ if-else문
if(조건식)
{
// if의 조건식이 true일 때 수행되는 문장
}
else
{
// if의 조건식이 false일 때 수행되는 문장
}
``else``는 독립적으로 사용되는 것이 아니라 ``if``와 같이 하나의 문장을 구성하는 형태로 사용된다.
조건식이 참일 경우 ``if``에 중괄호로 묶여있는 블록이 실행되고, 조건식이 거짓일 경우 ``else``에 묶여있는 블록이 실행된다.
■ if, else-if, else
if(조건 1)
{
// 조건1이 true일 때 수행되는 문장
}
else if(조건 2)
{
// 조건1이 false이고 조건 2가 true일 때 수행되는 문장
}
else
{
// 조건들이 모두 false일 때 수행되는 문장
}
셋 이상의 블록 중 하나를 선택해서 실행하는 구조이다. 중간에 ``else if``문을 추가해서 분기를 늘릴 수 있다. (@@if-else@@를 @@else@@블록을 대상으로 중첩시킨 형태이기 때문에) 하나라도 조건이 만족되어 해당 블록을 실행하고 나면, 마지막에 있는 @@else@@까지 그냥 건너뛴다.
삼항 연산자(조건 연산자)
(조건식) ? (조건식이 true일 때 실행할 문장) : (조건식이 false일 때 실행할 문장);
//ex) 아래와 같은 경우 대입 연산자보다 조건 연산자인 삼항연산자의 순위가 높아 먼저 진행된다.
int num3 = (num1 > num2) ? (num1) : (num2);
삼항 연산자(조건 연산자)는 간단한 ``if-else``문을 대신할 수 있는 연산자이다.
switch 문
switch(변수)
{
case [값1]:
// 변수가 값1일 때 실행할 문장
break;
case [값2]:
// 변수가 값2일 때 실행할 문장
break;
...
default:
// 변수가 모든 case값에 해당하지 않을때 실행할 문장
break;
}
if, else-if, else문과 기능이 비슷하다. 조건에 따라 다른데 보통 분기가 많아지면 사용한다.
switch에서 판별할 변수는 정수와 문자 자료형만 가능하다. (실수 자료형이나 문자열은 사용 불가)
case를 ``break``로 중단하지 않으면 그다음에 있는 ``case``, ``default``가 계속 실행된다. (이런 상황을 fall through라고 부른다.)
변수 : ``switch``문으로 전달되는 인자의 정보. 변수의 값에 따라 실행할 영역이 결정된다. (정수형이나 @@char@@형 변수여야 함. 대표적으로 @@int@@형 변수)
case 문 : 변수의 값에 따라 실행할 영역. 끝에 콜론( : )을 붙여야 한다. 위치를 표시하는 데 사용되어 레이블(label)이라고 한다.
break 문(선택) : 사용하면 ``case``문을 벗어난다. (없을 경우 다음 @@case@@까지 계속해서 실행됨)
default 레이블(선택) : 일치하는 ``case`` 레이블이 없을 경우에 실행되는 영역
■ case에서의 변수 선언
중괄호{ }로 묶고, 그 안에서 변수를 선언하면 된다. 선언된 변수는 해당 case문에서만 사용할 수 있고 중괄호를 벗어나면 사용할 수 없다.
반복문
while문
while(조건식) // 루프 선언문(loop statement)
{ // 루프 본체(loop body)및 변화식
// 조건식의 연산결과가 참(true)인 동안 반복될 문장
}
``while``문은 조건식을 만족하는 동안 괄호 안의 문장을 반복 실행하는 구조이다.
■ 중첩 while문
#include<stdio.h>
int main(void)
{
int dan = 2, num = 1;
while(num <= 9)
{
dan = 2;
while(dan <= 9)
{
printf("%d x %d = %d \t", dan, num, dan*num);
dan++;
}
num++;
printf("\n");
}
return 0;
}
``while``문 안에 ``while``문을 사용할 수 있다.
■ 무한루프
while(1)
{
printf("%d x %d = %d \n", dan, num, dan*num);
num++;
}
반복 조건에 ``0``이 아닌 값(참을 의미하는 값)이 올 경우 (보통 위의 코드처럼 ##1##을 넣는다.) 조건문이 항상 참이 되어 무한루프가 된다. ``break``문을 통해 반복문을 빠져나갈 수 있다.
do-while문
#include<stdio.h>
int main(void){
int total = 0, num = 0;
do
{
printf("정수 입력(0 to quit) : ");
scanf("%d", &num);
total += num;
}while(num != 0);
printf("합계 : %d \n", total);
return 0;
}
``do-while``문은 ``while``문과 달리 반복 조건을 뒷부분에서 검사하기 때문에 처음부터 반복 조건을 만족하지 못하면 한 번도 실행하지 않는 ``while``문과 달리, 반복문을 최소한 한 번 이상 실행하는 구조이다.
break: ``for``, ``while``, ``do-while``, ``switch``문에서 제어 흐름(반복)을 벗어나기 위해 사용한다.
continue: ``break``와 비슷하지만 다르다. ``break``는 제어 흐름(반복)을 중단하고 빠져나오는 반면, ``continue``는 제어 흐름(반복)을 유지한 상태에서 코드의 실행만 건너뛴다.
goto : 다중 루프를 빠져나올 때 사용되기도 한다.
for문
for(초기식 ; 조건식 ; 증감식) // 루프 선언문(loop statement)
{ // 루프 본체(loop body)
// 반복의 대상이 되는 문장들
}
``for``문도 ``while``문처럼 반복 작업을 수행하는 반복문이다. 초기식과 조건식, 증감식은 선택사항으로 필요하지 않다면 비워도 된다. 반복 횟수가 정해진 경우에는 ``for``문을 사용하고 그렇지 않은 경우 ``while``문을 주로 사용한다.
■ 중첩 for문
#include<stdio.h>
int main(void)
{
int i, j;
for(i = 1 ; i <= 9 ; i++)
{
for(j = 2 ; j <= 9 ; j++)
{
printf("%d x %d = %d\t", j, i, i*j);
}
printf("\n");
}
return 0;
}
■ 무한루프
for(;;)
{
...
}
``for``문에서 조건식이 비워지면 무조건 '참'으로 인식되어 무한루프가 된다.
제어문
break문
``break``문이 실행되면 ``break``문을 가장 가까이 감싸고 있는 반복문 하나를 빠져나오게 된다.
continue 문
반복문안에서 ``continue``를 실행하면 실행 중인 위치에 상관없이 반복문의 조건 검사 위치로 이동한다. (``continue`` 이후는 생략) 검사 결과 반복 조건이 여전히 '참'이면 반복 영역을 다시 실행한다.
특수문자, 서식 문자, 필드 폭 * 특수문자(Escape Sequence) * 서식 문자 * 필드 폭
표준 라이브러리와 printf, scanf 함수
표준 함수 : 기본적으로 제공되는 함수
표준 라이브러리 : 표준 함수들의 모임
printf 함수
// 서식문자의 위치는 제한이 없다.
printf("%d",1234);
printf("My age : %d\n", 20;
기본적으로 제공되는 표준 함수로 함수호출시 첫 번째로 전달되는 문자열을 모니터에 출력하는 기능을 한다.
사용하기 위해선 @@stdio.h@@ 헤더 파일을 선언해주어야 한다.
``%d`` : 서식 문자(conversion specifier)라고 하는데 출력의 형태를 지정하는 용도로 사용된다. 서식 문자의 삽입 위치에는 제한이 없어 다양하게 문자열을 조합해서 출력하는 것이 가능
- ``%d``는 10진수 정수 형태의 출력을 의미 - 두 번째 인자가 출력의 대상이 되며 특정 값이 아닌 연산식이 오는 것도 가능
scanf 함수
scanf("%d", &[변수 이름]);
int scanf(char const * const _Format, ...);
// 성공하면 가져온 값의 개수를 반환, 실패하면 EOF(-1)을 반환
//여러개 인 경우에는 콤마(,)로 구분한다.
scanf("%d %d %d", &num1, &num2, &num3);
``scanf`` 함수를 이용하면 키보드로부터 다양한 형태의 데이터를 입력받는 것이 가능하다. 서식 문자의 수를 조절하여 입력받는 데이터의 개수와 타입도 정할 수 있다. 값을 입력하고 @@enter@@키를 입력해야만 @@scanf@@함수의 데이터 입력이 완료되므로 주의한다.값을 여러 개 입력받는 경우 공백을 기준으로 데이터를 구분하므로 공백에 해당되는 스페이스바, 탭(tab) 또는 엔터(enter) 키를 입력해야 한다.
``%d`` : 서식 문자, ``printf``에서 사용한 것과 같다.
``&변수 이름`` : 입력받은 값을 지정한 변수에 저장한다.
■ EOF
End Of File의 약자로, 더이상 값을 읽을 수 없는 상태를 나타낸다. (파일의 끝) 콘솔(터미널, 명령 프롬프트)에서는 다음 키의 입력을 EOF로 정해놓았다. EOF는 ##stdio.h## 헤더에 정의되어 있으며 정수 ##-1##이다. 보통 EOF는 파일 처리 함수가 실패했을 때 반환된다.
Windows : ``Ctrl + Z``
Linux : ``Ctrl + D``
■ scanf로 공백까지 포함하여 입력받기
서식 지정자를 ``%[^\n]s``와 같이 지정하면 공백까지 포함하여 문자열을 입력받을 수 있다.
+ dev c++로 unsigned char형 변수 입력받기
#define __USE_MINGW_ANSI_STDIO 1 // Dev-C++(MinGW)에서 %hhu를 사용하기 위한 설정
scanf에서 unsigned char형 변수에 저장하려면 서식지정자로 ##%hhu##를 사용해야 하는데 Dev C++에서는 표준 scanf함수 대신 GNU scanf 함수를 사용하기 때문에 ##%hhu##를 사용할 수 없다. 그래서 위와 같이 매크로를 정의해주어야 표준 scanf 함수와 서식지정자 ##%hhu##를 사용할 수 있다.
특수문자, 서식문자, 필드 폭
``printf``와 ``scanf``의 f는 모두 formatted(서식이 지정된)를 의미한다. 그래서 서식 문자나 필드 폭등을 이용해서 입출력의 형태를 지정해줄 수 있다.
1. 특수문자(Escape Sequence)
특수문자 종류
설 명
\a
경고음 발생
\b
백스페이스(backspace)
\f
폼 피드 - Form Feed : 프린트 제어시 다음 페이지로 넘기는 기능 (프린터 출력을 위해 정의된 특수문자)
\n
개행 ,줄바꿈 (new line)
\r
Carriage Return : 커서의 위치를 커서가 위치한 줄의 맨 앞으로 위치하는 기능
\t
수평 탭
\v
수직 탭 (프린터 출력을 위해 정의된 특수문자)
\\
역슬래시(\)
\'
싱글쿼터(')
\"
더블쿼터(")
\?
물음표(?)
\ooo
아스키 문자 8진수 출력
\xhhh
아스키 문자 16진수 출력
2. 서식문자
서식문자 종류
출력 대상(자료형)
설 명
%d
char, short, int
부호 있는 10진(Decimal) 정수
%ld
long
부호 있는 10진(Decimal) 정수
%lld
long long
부호 있는 10진(Decimal) 정수
%u
unsigned int
부호 없는 10진 정수(양수만 표현 가능)
%o
unsigned int
부호 없는 8진(Octal) 정수
%x, %X
unsigned int
부호 없는 16진(Hexa_decimal) 정수
%f
float, double
10진형 부동(Floating) 소수점 실수 -> 기본적으로 소수점 이하 6자리까지 출력(나머지는 0으로 채움)
자동 형변환(묵시적 형변환) 1) 대입 연산의 전달 과정에서 발생하는 자동 형변환 2) 정수의 승격(Integral Promotion)에 의한 자동 형변환 3) 피연산자의 자료형 불일치로 발생하는 자동 형변환
강제 형변환(명시적 형변환)
자료형 변환 : 데이터의 표현 방식을 바꾸는 것
자료형의 확장과 축소
형 확장(type promotion) : 자료형을 섞어서 쓰면 컴파일러에서 암시적 형변환(implicit type conversion)을 하게 되는데 자료형의 크기가 큰 쪽, 표현 범위가 넓은 쪽으로 자동 변환된다. 이를 형 확장(type promotion)이라고 하며 값이 버려지지 않고 그대로 보전된다.
형 축소(type demotion) : 자료형의 크기가 작은 쪽, 표현범위가 좁은 쪽으로 변환되는 것을 형 축소(type demotion)라고 한다. 형 축소가 일어나면 컴파일할 때 값의 손실이 일어날 수 있다.
형변환의 종류
자동 형변환(묵시적 형변환) 1. 대입 연산의 전달 과정에서 발생하는 자동 형변환 2. 정수의 승격(Integral Promotion)에 의한 자동 형변환 3. 피연산자의 자료형 불일치로 발생하는 자동 형변환
강제 형변환(명시적 형변환)
1. 자동 형변환(묵시적 형변환)
1. 대입 연산의 전달 과정에서 발생하는 자동 형변환
int num = 3.1415; //double형 실수 3.1415를 int형으로 자동 형변환(3)
char ch = 129; //int형 리터럴인 129를 char형으로 자동 형변환(-127)
대입 연산자의 왼편과 오른편에 존재하는 두 피연산자의 자료형이 일치하지 않으면 왼편에 있는 피연산자를 대상으로 형 변환이 자동으로 일어난다. 그러나 위의 코드처럼 데이터의 표현 범위가 좁은 자료형으로의 형변환은 데이터 손실이 발생할 수 있으니 주의해야 한다.
정수 → 실수 : 값 손실 x (실수이기 때문에 오차는 존재함)
실수 → 정수 : 소수점 이하의 값 손실
byte 크기가 큰 정수 → byte 크기가 작은 정수 : 변환하고자 하는 정수의 byte 크기에 맞춰서 상위 byte를 소멸시킴 (이로 인해 부호가 바뀌는 경우도 있으니 주의)
2. 정수의 승격(Integral Promotion)에 의한 자동 형변환
일반적으로 CPU가 처리하기에 가장 적합한 크기의 정수 자료형이 ``int``형이기 때문에 ``int``형 연산의 속도가 다른 자료형의 연산속도에 비해서 동일하거나 더 빠르다. 그래서 ``int``보다 작은 크기의 정수형 데이터는 ``int``형으로 형변환 되어 연산이 진행된다. 이러한 형변환을 '정수의 승격(Integral Promotion)'이라고 한다.
3. 피연산자의 자료형 불일치로 발생하는 자동 형변환
CPU는 같은 자료형의 두 피연산자를 대상으로만 연산이 가능하도록 설계되어 있어 피연산자의 자료형이 서로 다른 경우 자동으로 형변환이 일어난다. 이때 형변환은 데이터의 손실을 최소화하는 방향으로 진행된다.
2. 강제 형변환(명시적 형변환)
형 변환 연산자를 이용해서 강제로 형 변환을 명령하는 것을 명시적 형변환이라고 한다. 형변환에 사용되는 소괄호`` ( ) ``를 가리켜 '형변환 연산자(type casting operator)'라고 하며, 연산의 결과로 변환된 값이 반환된다.
정수 자료형 * 정수 표현방식 * 음의 정수 * 정수 오버플로우 * 음수의 나머지 연산 * 정수 나눗셈 주의사항
실수 자료형 * 실수 표현 방식 * 실수 자료형의 최소값과 최대값 * 실수 자료형의 오버플로우와 언더플로우 * 실수 자료형과 증감 연산자 * 실수 자료형의 오차 * 실수 나눗셈 주의사항 * 실수의 나머지 연산
기본자료형의 종류와 데이터 표현 범위 * 정수 자료형의 최소값과 최대값 * 크기가 표시된 정수 자료형 * 실수 자료형의 정밀도
boolean 자료형(논리 자료형)
sizeof 연산자
아스키(ASCII) 코드 표
상수
리터럴(Literal) 상수 * 상수의 접미사
심볼릭(Symbolic) 상수 : const 상수
bit : 컴퓨터가 표현하는 데이터의 최소 단위로서 2진수 값 하나를 저장할 수 있는 메모리의 크기
ex) 8bit = 1byte
정수 자료형
정수 표현 방식
``1byte``의 정수라면 가장 왼쪽의 bit가 부호 비트가 되고 나머지 ``7bit``가 정수의 크기를 나타내는 데 사용된다.
MSB(Most Significant Bit) : 가장 왼쪽에 존재하는 bit로 부호를 표시하는 데 사용된다. 0 : 양수 1 : 음수
음의 정수
1의 보수법 : bit만 반대로 전환(`` 0 `` → `` 1 ``, `` 1 `` → `` 0 ``)
2의 보수법 : 1의 보수에서 +1 2의 보수가 양수와 더했을 때 @@0@@이 나오므로 컴퓨터는 2의 보수를 사용한다.
정수 오버플로우
c언어 표준에서는 부호 없는 정수와 부호 있는 정수의 오버플로우의 정의가 다르다.
부호 없는(unsigned) 정수 : 2의 거듭제곱 값으로 나머지 연산한 값(modulo power of 2) ex) unsigned char에 257을 할당할 경우 → 257 % 2^8 = 1
부호 있는(signed) 정수 : 정의되지 않은 행동(undefined behavior). 컴파일러에 따라 오버플로우의 값이 다를 수 있다.
음수의 나머지 연산
C99 표준에서 나머지 연산자는 a == (a / b) * b + a % b 로 정의하고 있다. 따라서 a % b를 연산하면 a의 부호를 따른다. ex1) 5 % (-3) → 2 → 5 == (5 / (-3)) * (-3) + 5 % (-3) → 5 == (-1) * (-3) + 2 → 5 == 3 + 2 ex2) (-5) % 3 → -2 → (-5) == ((-5) / 3) * 3 + (-5) % 3 → (-5) == (-1) * 3 + (-2) → (-5) == (-3) + (-2) ex3) (-5) % (-3) → -2 → (-5) == ((-5) / (-3)) * (-3) + (-5) % (-3) → (-5) == 1 * (-3) + (-2) → (-5) == (-3) + (-2)
정수 나눗셈 주의사항
정수를 0으로 나눌 수 없다. ``num1 = 1 / 0``과 같이 소스코드에서 정수를 0으로 직접 나누면 컴파일 에러가 발생한다. 변수에 0을 저장해서 나누면 컴파일 에러는 발생하지 않지만 실행하면 에러가 발생한다.
실수 자료형
실수 표현 방식
컴퓨터가 소수점 이하의 수를 표현하는 데 있어서 위와 같이 부동 소수점 방식을 사용하면 오차가 발생하게 된다. 이를 부동소수점 오차라고 한다.
실수 자료형의 최소값과 최대값
``float.h``에 정의되어 있다. ``%.40f``, ``%2f``처럼 서식지정자를 이용해서 출력하는 것도 가능하다. 소수점 자리가 긴 경우 ``%e``, ``%Le``를 사용하여 지수 표기법으로 출력하는 것도 가능하다.
float형 : ``FLT_MAX``, ``FLT_MIN``
double형 : ``DBL_MAX``, ``DBL_MIN``
long double형 : ``LDBL_MAX``, ``LDBL_MAX``
실수 자료형의 오버플로우와 언더플로우
C언어에서는 실수 언더플로우를 0 또는 쓰레기 값으로 처리한다. 오버플로우인 경우에는 실수와 달리 최소값이 아닌 무한대(infinity)가 된다. (출력은 ``inf``로 출력된다. ``-``붙으면 ``-inf``로도 출력된다.)
실수 자료형과 증감 연산자
실수에서도 ``++``, ``--``연산자를 사용할 수 있으며, 1을 증가하거나 감소시킨다. 정수부분만 바뀌면 소수점 이하 자리에는 영향을 미치지 않는다.
실수 자료형의 오차
실수를 유한개의 bit로 표현하기 위해서는 근사값으로 표현해야 한다. 이 때문에 오차가 발생하는데 이런 문제를 부동소수점 반올림 오차(rounding error)라고 한다. 그래서 실수는 연산 값을 ==로 비교하면 안 되고 FLT_EPSILON을 이용해서 비교해야 한다.
FLT_EPSILON : ``float.h`` 헤더에 정의되어 있으며 이 값을 머신 엡실론(machine epsilon)이라고 한다. 어떤 실수를 가장 가까운 부동 소수점 실수로 반올림하면 상대 오차는 항상 머신 엡실론 이하이다. 즉, 머신 엡실론은 반올림 오차의 상한 값이며 연산한 값과 비교할 값의 차이가 머신 엡실론보다 작거나 같으면 두 실수는 같은 값이라 할 수 있다. double형인 경우엔 ``DBL_EPSILON``, long이면 ``LDBL_EPSILON``이다.
#include <stdio.h>
int main(void)
{
int i;
float num1 = 0.0f;
float num2 = 0.1f;
// 0.1을 10번 더한다.
for (i = 0 ; i < 10 ; i++)
{
num1 = num1 + num2;
}
printf("num1 : %.16lf\n", num1);
if (num1 == 1.0f)
printf("true\n");
else
printf("false\n");
return 0;
}
0.1을 10번 더해서 1.0과 비교하는 것인데 반올림 오차가 발생해 버렸기 때문에 등호로 비교하면 잘못된 결과가 나온다.
#include <stdio.h>
#include <float.h> // float의 머신 엡실론 값 FLT_EPSILON이 정의된 헤더
#include <math.h> // float의 절대값을 구하는 fabsf 함수를 위한 헤더
int main(void)
{
int i;
float num1 = 0.0f;
float num2 = 0.1f;
// 0.1을 10번 더한다.
for (i = 0 ; i < 10 ; i++)
{
num1 = num1 + num2;
}
printf("num1 : %.16lf\n", num1);
// '연산한 값 - 비교할 값'의 절대값이 FLT_EPSILON이하면 같은 값으로 본다.
if (fabsf(num1 - 1.0f) <= FLT_EPSILON)
printf("true\n");
else
printf("false\n");
return 0;
}
연산할 값과 비교할 값의 차이를 구한 뒤 ``FLT_EPSILON``이하인지 판단해야 정확한 결과가 나온다.
fabsf 함수를 사용해서 절대값으로 만들면 음수도 정상적으로 판단할 수 있다.
실수 나눗셈 주의사항
실수 값에 0.0을 나누면 정수와 달리 실행이 중단되지 않고 무한대(inf)가 나온다. 변수를 ``INFINITY``와 비교하거나 ``isinf``함수를 사용하면 값이 무한대인지 검사할 수 있다. 무한대는 아니지만 실수가 아닌 수(허수처럼 실수로는 표현할 수 없는 수)는 NaN(Not a Number)라고 하며 ``isnan``함수로 검사할 수 있다.(모두 math.h 헤더에 정의되어있다.)
나머지 연산은 정수에서만 사용할 수 있고 실수에서는 사용할 수 없다. (컴파일 에러 발생) 그래서 실수의 나머지 연산을 할 때는 ``math.h``헤더의 fmod, fmodf, fmodl 함수를 사용한다.
fmod(나누어지는 수, 나누는 수) : double형 실수 ``double fmod(double _X, double _Y);``
fmodf(나누어지는 수, 나누는 수) : float형 실수 ``float fmodf(float _X, float _Y);``
fmodl(나누어지는 수, 나누는 수) : long double형 실수 ``long double fmodl(long double _X, long double _Y);``
기본자료형의 종류와 데이터 표현 범위
정수의 경우 일반적으로 CPU가 처리하기에 가장 적합한 크기의 자료형은 ##int##기 때문에 ##int##형 연산의 속도가 다른 자료형의 연산속도에 비해서 동일하거나 더 빠르다. (##int##보다 작은 자료형은 ##int##로 변환된 후에 연산된다.) 그래서 연산의 횟수가 빈번한 경우에는 저장되는 값의 크기가 작더라도 ##int##형 변수를 선언하는 것이 좋다. (실수 자료형은 ##double##형을 사용하는 것이 좋다.)
##int##보다 작은 자료형들은 데이터 양이 많아 연산속도보다 데이터 크기를 줄이는 것이 더 중요한 경우에 주로 사용된다. ex) MP3와 같은 음성 데이터나 영상 데이터
##unsigned##를 붙이면 MSB도 값을 표현하는 데 사용하므로 표현할 수 있는 값의 범위가 2배가 된다.
자료형
크기
값의 표현범위
정수형
char
1 byte
-128 이상 +127 이하
unsigned char
0이상 (128 + 127) 이하
short
2 byte
-32,768 이상 +32,767이하
unsigned short
0이상 (32,768 + 32,767)이하
int
4 byte
-2,147,483,648 이상 +2,147,483,647 이하
unsigned int
0이상 (2,147,483,648 + 2,147,483,647)이하
long
4 byte
-2,147,483,648 이상 +2,147,483,647 이하
unsigned long
0이상 (2,147,483,648 + 2,147,483,647)이하
long long
8 byte
-9,223,372,036,854,775,808 이상 +9,223,372,036,854,775,807 이하
``limits.h``에 정의되어있다. 정의된 최댓값을 넘어서면 오버플로우, 최소값보다 작아지면 언더플로우가 발생한다.
자료형
최소값
최대값
char
CHAR_MIN
CHAR_MAX
short
SHRT_MIN
SHRT_MAX
int
INT_MIN
INT_MAX
long
LONG_MIN
LONG_MAX
long long
LLONG_MIN
LLONG_MAX
unsigned char
0
UCHAR_MAX
unsigned short
0
USHRT_MAX
unsigned int
0
UINT_MAX
unsigned long
0
ULONG_MAX
unsigned long long
0
ULLONG_MAX
크기가 표시된 정수 자료형
자료형의 크기가 os마다 다르기 때문에 이식성을 위해서 사용하는 경우가 있다. ``stdint.h``에 포함되어 있다. (새로운 자료형이 아니라 내부적으로 typedef를 사용하여 운영체제에 맞게 자료형을 재정의 한 것이다.) 네트워크 프로그래밍이나 파일 압축 및 암호화 등 변수 크기에 민감한 프로그램을 만들 때 사용한다. + unsigned char는 파일이나 네트워크 패킷의 내용을 1byte 단위로 표현할 때 주로 사용한다. Window에서는 unsigned char를 BYTE 자료형으로 정의해서 사용한다.
부호 있는 정수(signed) 최대값 : ``INT8_MAX``, ``INT16_MAX``, ``INT32_MAX``, ``INT64_MAX``
부호 있는 정수(signed) 최소값 : ``INT8_MIN``, ``INT16_MIN``, ``INT32_MIN``, ``INT64_MIN``
부호 없는 정수(unsigned) 최대값 : ``UINT8_MAX``, ``UINT16_MAX``, ``UINT32_MAX``, ``UINT64_MAX``
부호 없는 정수(unsigned) 최소값 : 0
int_least32_t, int_fast32_t : least가 붙은 자료형은 최소 몇 bit만 만족하면 된다는 의미
실수 자료형의 정밀도
정밀도 : 오차가 발생하지 않는 소수점 이하의 자리수 ex) 정밀도가 15자리면 소수점 이하 15자리 까지는 오차가 발생하지 않음을 보장한다.
실수 자료형
소수점 이하 정밀도
byte 수
float
6자리
4 byte
double
15자리
8 byte
long double
18자리
12 byte
boolean 자료형(논리 자료형)
c에서는 0을 거짓, 0이 아닌 숫자를 참으로 사용하지만 ``stdbool.h``헤더를 사용하면 true를 참, false를 거짓으로 나타낼 수 있다. (출력할 때는 전용 서식지정자가 없기 때문에 ##%d(1, 0)##로 출력하거나, 문자열로 true, false를 직접 출력해야 한다.)
함수 모양을 하고 있지만 연산자이다. (함수는 실행 시점(run-time)에 호출되지만 sizeof는 컴파일 시점(compile-time)에 연산된다.) 메모리 공간에서 소모하는 메모리의 크기를 byte 단위로 계산해서 반환한다. 이 연산자의 피연산자로는 변수와 상수뿐만 아니라 자료형의 이름도 올 수 있기 때문에 이 연산자를 이용해서 자신이 사용하는 컴파일러의 자료형 별 바이트 크기도 확인할 수 있다.
sizeof 연산자의 형식
sizeof표현식
sizeof(자료형)
sizeof(표현식)
#include <stdio.h>
int main(void)
{
char ch = 9;
int inum = 1052;
double dnum = 3.1415;
printf("변수 ch의 크기 : %d \n", sizeof(ch));
printf("변수 inum의 크기 : %d \n", sizeof(inum));
printf("변수 dnum의 크기 : %d \n", sizeof(dnum));
printf("\nchar의 크기 : %d \n", sizeof(char));
printf("int의 크기 : %d \n", sizeof(int));
printf("long의 크기 : %d \n", sizeof(long));
printf("long long의 크기 : %d \n", sizeof(long long));
printf("float의 크기 : %d \n", sizeof(float));
printf("double의 크기 : %d \n", sizeof(double));
return 0;
}
``sizeof`` 연산자를 이용해서 각 자료형 및 변수의 byte 크기를 확인해보는 예제이다.
예를 들어 ``5.789`` 라는 실수 리터럴이 있을 때 이 값을 ``float``에 넣으면 값이 잘려 나갈 수 있다는 경고를 받는다. 선언한 자료형에 맞는 접미사를 붙여야 경고를 받지 않는다. 접미사들은 대소문자를 구분하지 않는다.
정수형 상수의 접미사
접미사
자료형
사용 예
생략
int
u, U
unsigned int
unsigned int n = 1025U
l, L
long
long n = 2467L
ul, UL
unsigned long
unsigned long n = 3456UL
ll, LL
long long
long long n = 5768LL
ull, ULL
unsigned long long
unsigned long long n = 8979ULL
실수형 상수의 접미사
접미사
자료형
사용 예
생략
double
f, F
float
float f = 3.15F
l, L
long double
long double f = 5.789L
2. 심볼릭(Symbolic) 상수 : const 상수
const int MAX = 100;
// 초기화 하지 않으면 쓰레기값으로 초기화 되버림
const int MAX;
변수와 마찬가지로 이름을 지니는 상수이다. 심볼릭 상수를 표현하는 방법은 두 가지가 있는데 하나는 ``const`` 키워드를 사용하는 방법이고 또 하나는 매크로를 이용하는 방법이다. @@const@@를 사용할 경우 상수이므로 선언과 동시에 초기화해야 하며 초기화를 하고 나면 값을 변경할 수 없다. 보통 상수는 모두 대문자로 표시하고 둘 이상의 단어를 연결할 때는 언더바(## _ ##)를 이용한다.
첫 번째 ``printf``문에서 ``num1``, ``num2``에 아무런 값을 저장하지 않았는데 ``0``과 ``38``이 출력되는 것을 확인할 수 있다. (컴퓨터마다 값은 다를 수 있음) 이런 값들을 쓰레기 값이라고 한다. 이처럼 변수를 선언만 하고 초기화하지 않은 상태로 값을 불러오면 쓰레기 값을 출력하기 때문에 변수를 선언하고 값을 불러올 때 주의해야 한다.
연산자
1. 단항 연산자
`` + ``, `` - ``가 피연산자가 하나인 단항 연산자로 사용되면 부호를 뜻하기도 한다.
2. 증가, 감소 연산자
단항 연산자이며 변수에 저장된 값을 1 증가 및 감소시키는 경우에 사용되는 연산자이다.
종 류
연산자
연산자의 기능
결합방향
전위 (prefix) 연산자
++num
값을 1 증가시킨 후, 속한 문장의 나머지를 진행(선 증가, 후 연산)
←
--num
값을 1 감소시킨 후, 속한 문장의 나머지를 진행(선 감소, 후 연산)
←
후위 (postfix) 연산자
num++
속한 문장을 먼저 진행한 후, 값을 1 증가시킴(선 연산, 후 증가)
→
num--
속한 문장을 먼저 진행한 후, 값을 1 감소시킴(선 연산, 후 감소)
→
#include <stdio.h>
int main(void)
{
int num1 = 10;
int num2 = 10;
int num3 = (num1--) + 2;
printf("num1 : %d \n", num1);
printf("num1++ : %d \n", num1++); // 후위 증가
printf("num1 : %d \n", num1);
printf("\nnum2 : %d \n", num2);
printf("++num2 : %d \n", ++num2); // 전위 증가
printf("num2 : %d \n", num2);
printf("\nnum3 : %d\n", num3);
}
전위 연산자와 후위 연산자의 차이를 비교해보는 예제이다.
후위 연산자(후위 증가, 후위 감소)는 ``( )``의 영향을 받지 않고, 다음 문장으로 넘어가야만 값의 증가 및 감소가 이뤄지는 것을 확인할 수 있다.
3. 이항 연산자(binary operator)
두 개의 피연산자를 요구하는 연산자를 가리켜 이항 연산자라고 한다.
연산자
연산자의 기능
결합방향
=
오른쪽에 있는 값을 왼쪽 변수에 대입
←
+
두 피연산자의 값을 더함
→
-
왼쪽 피연산자 값에서 오른쪽 피연산자 값을 뺌
→
*
두 피연산자의 값을 곱함
→
/
왼쪽 피연산자 값을 오른쪽의 피연산자 값으로 나눔
→
%
왼쪽의 피연산자 값을 오른쪽의 피연산자 값으로 나눴을 때 얻게되는 나머지를 반환
→
4. 비트 연산자
비트단위로 연산을 하는 연산자를 의미한다. 보통 ##>>1## 하면 값을 ##2##로 나눈 것과 같고 ##<<1##하면 값을 두 배한 것과 같기 때문에 상황에 따라서 곱셈과 나눗셈을 비트 이동 연산으로 대체할 수 있다.
연산자
연산자의 기능
결합방향
&
비트 단위로 AND 연산 ex) num1 & num2
→
|
비트 단위로 OR 연산 ex) num1 | num2
→
^
비트 단위로 XOR 연산 ex) num1 ^ num2
→
~
단항 연산자로서 피연산자의 모든 비트를 반전시킨다. ex) ~num1
←
<<
피연산자의 비트 열을 왼쪽으로 이동시킴 ex) num1 << 2 : 두 칸만큼 왼쪽으로 이동
→
>>
피연산자의 비트 열을 오른쪽으로 이동시킴 ex) num1 >> num2 : num2칸만큼 오른쪽으로 이동
→
#include <stdio.h>
int main(void)
{
int num1 = 15; // 00000000 00000000 00000000 00001111
int num2 = 20; // 00000000 00000000 00000000 00010100
printf("AND 연산의 결과 : %d\n", num1 & num2);
printf("OR 연산의 결과 : %d\n", num1 | num2);
printf("XOR 연산의 결과 : %d\n", num1 ^ num2);
printf("NOT 연산의 결과(~num1) : %d\n", ~num1);
printf("\nnum1 << 1 결과 : %d\n", num1 << 1);
printf("num1 << 2 결과 : %d\n", num1 << 2);
printf("num1 << 3 결과 : %d\n", num1 << 3);
printf("\nnum1 >> 1 결과 : %d\n", num1 >> 1);
printf("num1 >> 2 결과 : %d\n", num1 >> 2);
printf("num1 >> 3 결과 : %d\n", num1 >> 3);
return 0;
}
비트 연산자를 확인해보는 예제이다.
5. 복합 대입 연산자
다른 연산자와 합쳐진 형태의 대입 연산자를 복합 대입 연산자라고 한다.
연산자
의미
설명
+=
ex) a += b a = a + b
더한 값을 다시 자신에게 저장
-=
ex) a -= b a = a - b
뺀 값을 다시 자신에게 저장
*=
ex) a *= b a = a * b
곱한 값을 다시 자신에게 저장
/=
ex) a /= b a = a / b
나눈 값을 다시 자신에게 저장
%=
ex) a %= b a = a % b
나눈 나머지 값을 다시 자신에게 저장
<<=
ex) a <<= b a = a << b
왼쪽으로 비트이동 한 값을 다시 자신에게 저장
>>=
ex) a >>= b a = a >> b
오른쪽으로 비트이동 한 값을 다시 자신에게 저장
&=
ex) a &= b a = a & b
AND 연산한 값을 다시 자신에게 저장
^=
ex) a ^= b a = a ^ b
XOR 연산한 값을 다시 자신에게 저장
|=
ex) a |= b a = a | b
OR 연산한 값을 다시 자신에게 저장
6. 관계 연산자(비교 연산자)
관계 연산자는 대소와 동등의 관계를 따지는 연산자이다.
아래의 연산자들은 조건을 만족하면 ``1``(참, true)을, 만족하지 않으면 @@0@@(거짓, false)을 반환한다.
연산자
연산자의 기능
결합방향
<
ex) n1 < n2 n1이 n2보다 작은가?
→
>
ex) n1 > n2 n1이 n2보다 큰가?
→
==
ex) n1 == n2 n1이 n2와 같은가?
→
!=
ex) n1 != n2 n1이 n2와 다른가?(같지 않은가?)
→
<=
ex) n1 <= n2 n1이 n2보다 작거나 같은가?
→
>=
ex) n1 >= n2 n1이 n2보다 크거나 같은가?
→
7. 논리 연산자
논리 연산자란 ``AND``(논리곱), ``OR``(논리합), ``NOT``(논리 부정)을 표현하는 연산자이다.
연산자
연산자의 기능
결합방향
&&
ex) A && B A와 B모두 '참'이면 연산결과로 '참'을 반환(논리 AND)
→
||
ex) A || B A와 B 둘 중 하나라도 '참'이면 연산결과로 '참'을 반환(논리 OR)
→
!
ex) !A A가 '참'이면 '거짓', A가 '거짓'이면 '참'을 반환(논리 NOT)
←
8. 콤마 연산자(,)
둘 이상의 변수를 동시에 선언하거나, 둘 이상의 문장을 한 행(line)에 삽입하는 경우에 사용되는 연산자이다. 다른 연산자 들과 달리, 연산의 ``결과``가 아닌 '구분'을 목적으로 주로 사용된다.
■ 연산자의 우선순위와 결합방향
결합방향 : 우선순위가 동일한 두 연산자가 하나의 수식에 존재하는 경우, 어떠한 순서대로 연산하느냐를 결정해 놓은 것