
자료형은 자료를 담는 그릇과 같으며, 크게 상수와 변수로 나뉜다.
값이 한 번 정해지면 프로그램 실행 도중 변경할 수 없는 수로, 항상 고정된 값을 갖는 자료다.
< 리터럴(literal)과 상수 >
상수 : 값을 변경할 수 없는 변수(메모리의 주소값이 변하지 않음)
리터럴 : 변수에 할당되는 고정된 값 자체
(10, 3,14, 'A', "ALPHABET" -> 리터럴 상수, 문자 그대로 상수, 일반적으로 약속되어 정해졌기 때문에 '한정자'라고도 함)
| 구분 | 예 | 비고 |
|---|---|---|
| 10진 상수 | 10, -10, 999 | 0~9까지의 숫자, 0으로 시작할 수 없음 |
| 8진 상수 | 011, 055 | 0~7까지의 숫자를 사용, 숫자 앞에 0을 붙임 |
| 16진 상수 | 0xas, 0X2A | 0~9와 A~F를 사용, 숫자 앞에 0x를 붙임 |
| unsigned형 상수 | 12u, 067u, 0XFAU | 부호 없는 상수를 표현, 숫자 뒤에 U나 u를 붙임 |
| long형 상수 | 123456l, 0XFFL | 큰 길이의 정수를 표현, 숫자 뒤에 l이나 L을 붙임 |
소수점의 위치가 고정되지 않고 떠다닐 수 있어서 부동소수점(floating point)형 상수라고도 하며, 정수형보다 큰 값이나 작은 값을 처리하는 데 사용된다. ❗️double형을 기본 자료형으로 사용
| 구분 | 예 | 비고 |
|---|---|---|
| 소수 형식 | 12.345, 3.14, .5 | 소수점을 사용하여 표현 |
| 지수 형식 | 12E3(=12000), 5e-2(=0.05) | 10진수와 e(E)를 사용하여 표현 |
| float형 | 3.14f, 3.14E-3F | 숫자 뒤에 f나 F를 붙임 |
| long double형 | 3.14l, 3.14E-3L | 숫자 뒤에 l이나 L을 붙임 |
작은 따옴표 한 쌍('')으로 묶인 1개의 영문자나 숫자문자이다. 문자형 상수는 내부적으로 해당 문자의 ASCII 코드값이 사용된다. 또한 키보드에 나타나 있지 않지만 특수한 기능을 가진 escape 문자가 있다.
| escape 문자 | 기능 |
|---|---|
| \a | 경고음 출력 |
| \b | 백스페이스 |
| \f | 새 페이지 |
| \n | 출력 시 줄 바꿈(특히 printf 함수에서 꼭 쓰임) |
| \r | 커서를 행의 시작 위치로 이동 |
| \t | 수평 탭 |
| \0 | ASCII 코드값이 0인 문자(null문자) |
큰 따옴표 한 쌍("")으로 묶인 여러 개의 영문자와 숫자로 이루어진 상수이다. 문자열 상수가 기억공간에 보관될 때에는 문자열의 끝을 표시해 주기 위해서 맨 끝에 null 문자 \0를 추가한다.
예를 들어 문자열 "COMPUTER SCIENCE" → C O M P U T E R S C I E N C E \0 는 중간의 공백 문자와 마지막의 '\0'까지 합쳐 총 17개의 연속된 기억공간에 보관된다.
변수는 값을 저장하는 메모리 영역이다. 이 값은 프로그램 실행 도중 수시로 변경될 수 있기 때문에(변수의 특성), 사용하기 전에 먼저 선언을 해야 컴파일러가 기억공간에서 일정 부분을 확보할 수 있다.
선언
선언과 정의(초기화)
⌨️ 예제 1
#include <stdio.h>
int main() {
int a; // 변수 선언(a라는 이름의 int형 변수를 생성)
a = 3; // 변수 정의(변수 a에 3이라는 값을 대입)
printf("%d\n", a); // 변수 a 값 출력
a = 5; // 같은 변수에 대입을 두 번째 했기 때문에 앞선 값 3이 지워지고 5로 대체
printf("%d\n", a); // 변수 a 값 출력
}
🖥️ 실행 결과
3
5
❗️"a = 3;" 에서 '='는 '같다'는 뜻이 아니라, a라고 이름을 지은 기억공간에 3이라는 값을 '저장'하라는 의미다.
변수 선언을 위해선 변수의 이름과 자료형(자료의 형태)을 결정해야 한다. C 언어에서 각각의 자료형에 저장될 수 있는 자료의 크기와 표현될 수 있는 범위는 다음과 같다.
✏️ 데이터의 크기 → bit, byte
비트(bit) : 한 자리 이진수(0, 1)만 나타낼 수 있는 가장 작은 단위이다.
바이트(byte) : 8bit는 1byte가 된다. 1byte는 영문자나 숫자를 1개 저장할 수 있는 크기이다.
(바이트는 컴퓨터에서 데이터를 처리하는 가장 작은 단위!)
정수형에는 char, int가 있으며,
앞에 크기를 나타내는 short, long 또는 부호 있는 정수 signed, 부호 없는 정수 unsigned라는 키워드를 붙여 정의할 수 있다(부호 비트의 사용 여부). signed 키워드는 보통 생략하며, int는 다른 키워드와 같이 사용할 시 생략 가능하다.
✏️ 부호 비트
컴퓨터에서 이진수로 수를 표현할 때, 할당된 n비트 중 최상위(맨 앞) 1비트를 부호 비트로 사용할 수 있다.
부호 비트가 0이면 양의 정수, 1이면 음의 정수라는 의미다.
unsigned는 음수를 저장할 수 없는 대신 양수값의 표현범위가 signed의 2배로 늘어난다.
| 정수형 | 범위 | 크기 |
|---|---|---|
| (signed) short (int) | -32,768 ~ 32,767 | 2byte |
| unsigned short (int) | 0 ~ 65,535 | 2byte |
| (signed) int | -2,147,483,648 ~ 2,147,483,647 | 4byte |
| unsigned (int) | 0 ~ 4,294,967,295 | 4byte |
| (signed) long (int) | -2,147,483,648 ~ 2,147,483,647 | 4byte |
| unsigned long (int) | 0 ~ 4,294,967,295 | 4byte |
| (signed) long long (int) | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 | 8byte |
| unsigned long long (int) | 0~18,446,744,073,709,551,615 | 8byte |
int형은 원래 사용하는 컴퓨터의 시스템에 따라 자동으로 크기가 결정됐으나, 최근 들어서는 대체로 long의 크기인 4byte로 쓰인다.
실수형은 float, double, long double형이 있으며, 기본형은 double이다.
(float는 실수를 저장하기엔 저장공간이 작아서 숫자나 계산이 복잡해지면 오차가 발생하게 된다. double을 사용하면 크기가 2배로 늘어서 정확도를 높일 수 있다)
| 실수형 | 범위 | 크기 |
|---|---|---|
| float | ~ | 4byte |
| double | ~ | 8byte |
| long double | ~ | 8byte |
문자형은 ASCII 코드를 사용하여 처리한다. 대문자 A~Z는 십진수 65~90, 소문자 a~z는 97~122, 숫자 0~9는 48~57로 저장됨을 확인할 수 있다.

| 문자형 | 범위 | 크기 |
|---|---|---|
| char | -128 ~ 127 | 1byte |
| unsigned char | 0 ~ 255 | 1byte |
char는 반각문자 하나를 저장할 수 있는 1바이트 크기의 자료형이다.
✏️ 전각문자와 반각문자
전각문자(全角文字) : 하나의 문자가 정사각형을 이룬다. 예) 한글, 한자, 일본어, 러시아어, 전각 숫자 등
반각문자(半角文字) : 가로폭이 전각문자의 절반으로 줄어든 문자다. 예) 영문자, 숫자, 문장부호, 기호 등
⌨️ 예제 2
#include <stdio.h>
int main() {
char a = 99; // 변수 초기화
printf("%d\n", a); // 변수 a를 정수로 변환한 값 출력
printf("%c\n", a); // 변수 a의 문자로 변환한 값 출력
printf("%d\n", 'c'); // 문자 'c'를 정수로 변환한 값 출력
printf("%c\n", 'c'); // 문자 'c'를 문자로 변환한 값 출력
}
🖥️ 실행 결과
99
c
99
c
소문자 'c'는 99라는 숫자값과 대응된다는 것을 확인할 수 있다.
⌨️ 예제 3
//입력한 문자에 대응하는 아스키 값을 출력하는 프로그램
#include <stdio.h>
int main() {
char a;
printf("문자 입력 : ");
scanf("%c", &a);
printf("%c의 ASCII 값 : %d\n", a, a);
}
🖥️ 실행 결과
문자 입력 : g [Enter↵]
g의 ASCII 값 : 103
문자열(string)은 크기가 일정하지 않으므로 자료형이 없다. 다만 문자열은 문자들의 집합이기 때문에 char형 변수를 모은 배열을 사용해서 처리할 수 있다.
참고 : [C] 배열
열거형은 서로 관련있는 정수형 상수들에 이름을 붙여 하나의 집합으로 묶은 것이다. 단어를 열거자로 사용할 수 있으며, 열거자의 값은 디폴트로 첫 번째가 0으로 시작하여 그 다음 원소는 이전 원소의 값보다 하나 더 큰 값을 가진다.
⌨️ 예제 4
#include <stdio.h>
int main() {
enum DAY1 {SUN, MON, TUE, WED, THU, FRI, SAT} d1; /* enum DAY1형 변수 d1 같이 선언
(초깃값은 자동으로 0부터 시작) */
enum DAY2 {sun = 2, mon, tue, wed, thu, fri, sat}; // 초깃값을 2로 지정함
enum DAY2 d2; // enum DAY2형 변수 d2 따로 선언
d1 = FRI;
d2 = fri;
printf("열거형 d1의 FRI에 저장된 값은 %d 입니다.\n", d1);
printf("열거형 d2의 fri에 저장된 값은 %d 입니다.\n", d2);
}
🖥️ 실행 결과
열거형 d1의 FRI에 저장된 값은 5 입니다.
열거형 d2의 fri에 저장된 값은 7 입니다.
void : 리턴값이 없는 함수의 자료형
bool : 진리값을 저장하는 1byte 크기의 논리 자료형
✏️ 논리 자료형(boolean, bool 타입)
C++에서는 기본 자료형으로 지정되어 있지만, C에는 C99 표준부터 도입된 자료형이다.
C 언어 환경에서 bool자료형이 필요한 경우 <stdbool.h>를 include해야 한다.
이 헤더 파일에는 bool, true, false가 지정되어 있기 때문에
true는 참으로, false는 거짓으로 표현할 수 있다.
변수 선언 시 주의해야 할 사항이 3가지 있다.
변수를 선언할 때는 해당 변수에 저장할 자료의 최솟값과 최댓값의 범위 내에 부합하는 자료형을 지정해야 한다. 변수가 가지는 범위보다 더 큰 값을 대입하면 오버플로(overflow), 더 작은 값을 대입하면 언더플로(underflow)가 발생하여 원하지 않는 결과가 나올 수 있다.
⌨️ 예제 5
#include <stdio.h>
void main() {
short num1, num2;
// 두 변수에 short형의 범위(-32,768 ~ 32,767)를 벗어나는 값을 설정하기
num1 = 32767 + 1; // short형의 최댓값에서 +1 한 값
num2 = -32768 - 1; // short형의 최솟값에서 -1 한 값
printf("num1 = %d\n", num1);
printf("num2 = %d\n", num2);
}
🖥️ 실행 결과
num1 = -32768
num2 = 32767
🛠️ 코드 수정
범위가 더 넓은 int형 등으로 수정하면 각각 '32768', '-32769'라는 정확한 연산 결과를 얻을 수 있다.
변수의 선언 위치는 변수가 사용되는 범위를 결정하므로 매우 중요하다. 함수의 외부에서 선언된 변수는 프로그램 어디서나 통용되는 전역변수로, 프로그램이 실행되는 동안 항상 존재하는 자료 영역에 저장된다. 지역변수는 함수의 내부에서 선언되어, 그 함수 안에서만 인식되는 변수로, 임시 기억공간인 스택 영역에 저장된다.
⌨️ 예제 6
#include <stdio.h>
int a = 100; // 전역변수 a
void func() {
int a = 200;
printf("func()에서 a의 값 = %d\n", a); // func()의 지역변수 a 출력
}
int main() {
printf("main에서 a의 값 = %d\n", a); // 전역변수 출력
func();
}
🖥️ 실행 결과
main에서 a의 값 = 100
func()에서 a의 값 = 200
선언된 변수에 최초로 특정 값을 부여하는 것을 변수의 초기화라고 한다(변수 선언과 정의를 함께 하는 것).
변수를 초기화하지 않으면 기억공간에 존재하고 있던 기존의 값(쓰레기값)을 그대로 유지하기 때문에 엉뚱한 값이 나올 수 있다.
⌨️ 예제 7
#include <stdio.h>
int main() {
int i, sum; // 변수 i, sum 선언
//sum = 0; // 변수 sum을 0으로 초기화하는 과정을 임의로 생략
for(i = 1; i <= 10; i++) // 변수 i를 1로 초기화한 후 사용
sum = sum + i;
printf("1부터 10까지의 합 = %d\n", sum);
}
🖥️ 실행 결과
1부터 10까지의 합 = 32814
🛠️ 코드 수정
생략했던 "sum = 0;" 부분을 포함하면 정상적인 값인 '55'을 얻을 수 있다.