2단원 — 변수와 자료형
값을 메모리에 담아 두고 이름으로 부를 수 있게 하는 것이 **변수**입니다. 어떤 종류의 값을, 몇 바이트짜리 상자에 담을지 결정하는 것이 **자료형**입니다.
이 강의에서 배우는 것
- 1변수의 선언/초기화/대입을 구분한다.
- 2C의 기본 자료형(`int`, `float`, `double`, `char`)의 크기와 용도를 구별한다.
- 3`sizeof` 연산자로 자료형 크기를 확인한다.
- 4`const`, `#define`으로 상수를 정의한다.
왜 자료형이 여러 개일까?
값을 담을 수 있다면 무조건 큰 상자가 좋아 보이지만, 실제로는 그렇지 않습니다.
- 정수 100을 8바이트 `long`에 담으면 7바이트가 낭비됩니다.
- 30억(약 31억)을 4바이트 `int`에 담으면 **오버플로**가 일어납니다.
- 3.14는 `int`로는 절대 표현할 수 없습니다.
자료형은 "이 메모리 슬롯이 **어떤 모양의 값**을 담는지" 를 정해 컴파일러가 산술/입출력/저장 방식을 결정하게 해 줍니다.
핵심 개념
1) 변수의 일생
int age; // 선언만 (값은 쓰레기 값)
age = 20; // 대입
int year = 2026; // 선언과 동시에 초기화메모리 그림으로 보면:
선언 직후 대입 후
┌──────────────┐ ┌──────────────┐
│ age : ??? │ │ age : 20 │
└──────────────┘ └──────────────┘2) 기본 자료형 (64-bit Linux 기준)
| 자료형 | 크기 | 표현 범위 (대략) |
|---|---|---|
| `char` | 1 byte | -128 ~ 127 |
| `short` | 2 byte | -32,768 ~ 32,767 |
| `int` | 4 byte | -21억 ~ +21억 |
| `long` | 8 byte | 매우 큼 |
| `float` | 4 byte | 약 7자리 정밀도 |
| `double` | 8 byte | 약 15자리 정밀도 |
`unsigned`를 붙이면 음수 영역을 포기하고 양의 범위가 두 배가 됩니다.
3) 상수: 변하지 않는 값에 이름 붙이기
#define PI 3.14159 // 전처리기 매크로 — 컴파일 전에 텍스트 치환
const int MAX = 100; // 일반 변수지만 변경 금지리터럴(`3.14159`)을 코드 곳곳에 흩뿌리지 말고 한 군데에 이름을 붙입니다. 값이 바뀌면 정의 한 곳만 고치면 됩니다.
4) `sizeof` 연산자
자료형이나 변수가 **몇 바이트**를 차지하는지 알려 줍니다. 운영체제와 컴파일러에 따라 달라질 수 있어, 직접 출력해 두면 디버깅에 유용합니다.
printf("%zu\n", sizeof(int)); // 보통 4예제로 보기
예제 1 — `ex01_variables.c` : 선언 → 대입 → 갱신
int age = 20;
int year;
year = 2026;
printf("나이: %d세\n", age);
printf("연도: %d년\n", year);
age = age + 1;
printf("내년 나이: %d세\n", age);**실행 결과**
나이: 20세
연도: 2026년
내년 나이: 21세핵심: `=`는 "같다"가 아니라 **"오른쪽 값을 왼쪽에 대입"** 입니다.
예제 2 — `ex02_types.c` : 자료형별 출력 서식
int score = 95;
float ratio = 0.75f;
double price = 19999.99;
char grade = 'A';**실행 결과**
정수 (%d): 95
실수 (%f): 0.750000
실수 (%.2f): 0.75
배정밀도 (%lf): 19999.990000
문자 (%c): A
문자의 ASCII (%d): 65핵심: 문자(`'A'`)는 **정수 코드(65)** 로도 출력됩니다. 즉 `char`는 작은 정수입니다.
예제 3 — `ex03_sizeof.c` : 자료형 크기 직접 확인
**실행 결과**
char = 1 byte
short = 2 byte
int = 4 byte
long = 8 byte
float = 4 byte
double = 8 byte
변수 a의 크기: 4 byte핵심: `sizeof`의 결과는 **`size_t`** 형이라서 `printf`는 `%zu`로 출력합니다.
예제 4 — `ex04_const.c` : 상수의 두 가지 방식
**실행 결과**
원주율(매크로): 3.141590
최대 사용자(매크로): 100
일주일(const): 7일
반지름 5.0인 원의 넓이: 78.539750핵심: `const`는 변수처럼 자료형 검사를 받고, `#define`은 단순 텍스트 치환입니다.
다른 시각으로 보기 — "라벨 붙은 상자"
변수 = 라벨이 붙은 메모리 상자
자료형 = 그 상자의 크기와 모양
┌─────────┐ ┌─────────┐ ┌─────────────┐
│ age │ │ score │ │ price │
│ int │ │ int │ │ double │
│ 4 byte │ │ 4 byte │ │ 8 byte │
│ [20] │ │ [95] │ │ [19999.99] │
└─────────┘ └─────────┘ └─────────────┘같은 상자에 다른 모양 값을 넣으려 하면(`int`에 3.14 대입) 컴파일러가 **소수부를 잘라**(절단) 값을 욱여넣습니다.
자주 하는 실수
- **초기화 안 한 변수 사용**: `int x; printf("%d", x);` → 쓰레기 값 출력.
- **정수 오버플로**: `int n = 3000000000;` → 표현 범위 초과로 음수가 될 수 있음.
- **부동소수 오차**: `float`로 0.1을 100번 더해도 정확히 10이 되지 않습니다.
- **`%d` vs `%f` 혼동**: 자료형과 서식이 안 맞으면 쓰레기 출력.
- **`'A'` vs `"A"` 혼동**: 작은따옴표는 문자(1바이트), 큰따옴표는 문자열(2바이트, `'A'`+`'\0'`).
정리
- 변수는 메모리에 이름을 붙이는 것이고, 자료형은 그 메모리의 크기와 해석 방식이다.
- 64비트 Linux에서 `int`=4, `double`=8 바이트가 기본.
- 상수에는 의미 있는 이름을 붙여 매직 넘버를 줄인다.
- `sizeof`로 직접 크기를 확인하는 습관을 들이자.
- 자료형과 서식 지정자(`%d`, `%f` 등)는 짝을 맞춰야 한다.
직접 해 보기
cd src
gcc -std=c11 -Wall -o ex01 ex01_variables.c && ./ex01
gcc -std=c11 -Wall -o ex02 ex02_types.c && ./ex02
gcc -std=c11 -Wall -o ex03 ex03_sizeof.c && ./ex03
gcc -std=c11 -Wall -o ex04 ex04_const.c && ./ex04응용:
- `ex03_sizeof.c`에 `long long`, `unsigned int`도 추가해 출력해 보세요.
- `ex04_const.c`의 `DAYS_IN_WEEK = 8;` 주석을 풀어 컴파일러가 어떤 오류를 내는지 확인.
💻 예제 (examples)
실제로 컴파일·실행해 결과를 확인할 수 있는 예제입니다.
#include <stdio.h>
int main(void) {
int age = 20;
int year;
year = 2026;
printf("나이: %d세\n", age);
printf("연도: %d년\n", year);
age = age + 1;
printf("내년 나이: %d세\n", age);
return 0;
}
나이: 20세
연도: 2026년
내년 나이: 21세#include <stdio.h>
int main(void) {
int score = 95;
float ratio = 0.75f;
double price = 19999.99;
char grade = 'A';
printf("정수 (%%d): %d\n", score);
printf("실수 (%%f): %f\n", ratio);
printf("실수 (%%.2f): %.2f\n", ratio);
printf("배정밀도 (%%lf): %lf\n", price);
printf("문자 (%%c): %c\n", grade);
printf("문자의 ASCII (%%d): %d\n", grade);
return 0;
}
정수 (%d): 95
실수 (%f): 0.750000
실수 (%.2f): 0.75
배정밀도 (%lf): 19999.990000
문자 (%c): A
문자의 ASCII (%d): 65#include <stdio.h>
int main(void) {
printf("char = %zu byte\n", sizeof(char));
printf("short = %zu byte\n", sizeof(short));
printf("int = %zu byte\n", sizeof(int));
printf("long = %zu byte\n", sizeof(long));
printf("float = %zu byte\n", sizeof(float));
printf("double = %zu byte\n", sizeof(double));
int a = 0;
printf("변수 a의 크기: %zu byte\n", sizeof(a));
return 0;
}
char = 1 byte
short = 2 byte
int = 4 byte
long = 8 byte
float = 4 byte
double = 8 byte
변수 a의 크기: 4 byte#include <stdio.h>
#define PI 3.14159
#define MAX_USERS 100
int main(void) {
const int DAYS_IN_WEEK = 7;
double radius = 5.0;
printf("원주율(매크로): %f\n", PI);
printf("최대 사용자(매크로): %d\n", MAX_USERS);
printf("일주일(const): %d일\n", DAYS_IN_WEEK);
printf("반지름 %.1f인 원의 넓이: %f\n", radius, PI * radius * radius);
/* DAYS_IN_WEEK = 8; // 컴파일 오류 - const는 변경 불가 */
return 0;
}
원주율(매크로): 3.141590
최대 사용자(매크로): 100
일주일(const): 7일
반지름 5.0인 원의 넓이: 78.539750📝 과제 (exercises)
직접 풀어보고, 막힐 때 정답을 펼쳐 비교해보세요.
문제 1 (hw01.c)
목표: 키(`height`, 단위 cm)와 몸무게(`weight`, 단위 kg)를 변수로 선언하고 다음 형식대로 출력하세요. 값은 자유롭게 정해도 됩니다.
- 파일명: hw01.c
키: 175.5 cm
몸무게: 68.2 kg▶정답 코드 펼치기 / 접기
#include <stdio.h>
int main(void) {
float height = 175.5f;
float weight = 68.2f;
printf("키: %.1f cm\n", height);
printf("몸무게: %.1f kg\n", weight);
return 0;
}
키: 175.5 cm
몸무게: 68.2 kg문제 2 (hw02.c)
목표: 한 변의 길이가 `side = 4`인 정육면체의 부피와 겉넓이를 출력하세요.
- 파일명: hw02.c
부피: 64
겉넓이: 96▶정답 코드 펼치기 / 접기
#include <stdio.h>
int main(void) {
int side = 4;
int volume = side * side * side;
int surface = 6 * side * side;
printf("부피: %d\n", volume);
printf("겉넓이: %d\n", surface);
return 0;
}
부피: 64
겉넓이: 96문제 3 (hw03.c)
목표: `#define`으로 `LIGHT_SPEED`를 `299792458` (m/s)로 정의하고, 빛이 1초 동안 가는 거리를 km 단위로 출력하세요.
- 파일명: hw03.c
▶정답 코드 펼치기 / 접기
#include <stdio.h>
#define LIGHT_SPEED 299792458 /* m/s */
int main(void) {
long meters = LIGHT_SPEED;
long km = meters / 1000;
printf("빛은 1초 동안 약 %ld km 이동합니다.\n", km);
return 0;
}