C#LAB
C# 1.3 · 1부. 기초

변수와 데이터 타입

값을 담는 상자에 이름을 붙이는 법, 그리고 C#이 그 상자의 모양(타입)을 왜 미리 정해두라고 하는지 알아봅니다.

예상 학습 시간 14분 실행 단추가 있는 예제는 고쳐서 실행해 볼 수 있습니다 난이도 입문
개념 설명

변수, 그리고 타입을 미리 정하는 이유

변수(variable)는 값을 저장하는, 이름이 붙은 메모리 공간입니다. C#은 정적 타입 언어라서 변수를 선언할 때 어떤 종류의 값을 담을지 타입을 함께 정해야 합니다. 컴파일러가 이 정보를 미리 알기 때문에, 실행 전에 int에 문자열을 넣는 것 같은 실수를 잡아낼 수 있습니다.

타입을 적는 것이 번거로워 보이지만, 잘못을 실행하기 전에 잡아 준다는 것이 그 값을 합니다. 타입을 정해 두지 않는 언어에서는 같은 실수가 프로그램이 한참 돌다가, 그것도 엉뚱한 자리에서 드러납니다.

C#의 타입은 크게 두 가지로 나뉩니다.

  • 값 형식(value type)int, double, bool처럼 변수 자체에 값이 직접 저장됩니다.
  • 참조 형식(reference type) — 배열이나 클래스처럼 변수에는 실제 데이터가 있는 위치만 저장됩니다.

이 차이는 다른 변수에 담을 때 드러납니다. 아래 상세 사용법에서 직접 보겠습니다.

최소 예제 · 편집 가능

기본 타입으로 변수 선언하기

아래 코드는 브라우저 안에서 실제로 실행됩니다. 고쳐서 눌러 보셔도 됩니다.

Program.cs
int age = 27;
double price = 19.99;
bool isStudent = true;
string name = "홍길동";

Console.WriteLine($"{name}님은 {age}살이고, 학생 여부는 {isStudent}입니다.");
출력
홍길동님은 27살이고, 학생 여부는 True입니다.

코드는 고쳐서 실행해 볼 수 있습니다. 처음 누를 때만 실행기를 내려받느라 잠시 걸립니다. 적은 코드는 서버로 나가지 않습니다.

true 라고 담았는데 화면에는 True 로 나옵니다. 코드에 적는 말과 글자로 바뀐 결과가 다른 것인데, 나중에 이 값을 글자로 견줄 일이 있다면 이 점을 기억해두면 좋습니다.

상세 사용법

자주 사용하는 기본 타입

타입설명예시
int정수 (약 -21억 ~ 21억)int count = 3;
long더 큰 범위의 정수long big = 10000000000;
double실수 (소수점 값)double pi = 3.14;
decimal정밀한 소수 (금액 계산용)decimal price = 1990.50m;
bool참/거짓bool done = false;
char문자 하나char grade = 'A';
string문자열string city = "서울";

돈을 다룰 때는 double 이 아니라 decimal 입니다. double 은 2진법으로 소수를 담느라 0.1 같은 값을 정확히 담지 못해, 더하다 보면 아주 작은 오차가 쌓입니다. 금액에서는 그 오차가 그대로 틀린 값이 됩니다.

담을 때와 옮길 때가 다릅니다

앞에서 타입이 두 가지로 나뉜다고 했습니다. 그 차이는 한 변수를 다른 변수에 담을 때 드러납니다. 값 형식은 값이 통째로 복사되지만, 참조 형식은 위치만 복사되어 둘이 같은 것을 가리키게 됩니다.

값 형식 — 값이 복사됩니다
int a = 10;
int b = a;      // 값을 복사

b = 99;

// a 는 10
// b 는 99
참조 형식 — 위치가 복사됩니다
int[] a = { 10, 20 };
int[] b = a;    // 위치를 복사

b[0] = 99;

// a[0] 도 99
// 둘이 같은 것을 가리킵니다

오른쪽에서 a 를 건드리지 않았는데 a[0] 이 바뀐 것이 핵심입니다. b 는 값을 복사해 온 것이 아니라 같은 데이터를 가리키는 다른 이름일 뿐입니다.

여기서 사용한 대괄호는 값을 여럿 담아 두는 방법이며 1.7에서 자세히 다룹니다. 지금은 값 형식과 참조 형식이 다르게 움직인다는 것만 보면 됩니다. 이 차이는 1.8에서 메서드에 값을 넘길 때, 그리고 2부에서 클래스를 다룰 때 다시 나옵니다.

타입을 적는 수고를 더는 var

var 키워드를 사용하면 오른쪽 값을 보고 컴파일러가 타입을 자동으로 추론합니다. 타입이 사라지는 게 아니라, 타입을 적는 수고만 줄어드는 것입니다. 한번 정해진 뒤에는 다른 타입을 담을 수 없습니다.

var age = 27;      // 컴파일러가 int로 추론
var name = "홍길동";  // 컴파일러가 string으로 추론

age = "스물일곱";    // 컴파일 오류 — 이미 int 로 정해졌습니다

오른쪽만 보고 무엇인지 알기 어렵다면 타입을 적는 편이 낫습니다. var n = Get(); 는 짧지만, 읽는 사람이 Get 을 찾아가 보아야 무엇이 담기는지 압니다.

값이 없을 수도 있을 때

값 형식은 기본적으로 값을 반드시 가져야 합니다. 물음표를 붙이면 (int?) "값이 없을 수도 있음"을 허용할 수 있습니다. 아직 입력받지 않았거나 해당 사항이 없는 자리를 나타낼 때 사용합니다.

int? age = null;      // 아직 모릅니다

if (age.HasValue) {
    Console.WriteLine(age.Value);
} else {
    Console.WriteLine("나이를 아직 적지 않았습니다.");
}
버전 배지

이 문법, 몇 버전부터 사용할 수 있나요

1.0
2.0
3.0
4.0
5.0
6.0
8.0
9.0
14.0
  • 2.0int? — nullable 값 형식
  • 3.0var — 타입 추론 키워드
C# 3.0+

var는 C# 3.0(2007)부터 사용할 수 있습니다. 그 이전 버전에서는 모든 변수에 타입을 직접 명시해야 했습니다. int? 같은 nullable 값 형식은 더 이전인 C# 2.0(2005)부터 가능합니다. 참조 형식에도 같은 표시를 할 수 있게 된 것은 한참 뒤인 C# 8.0입니다.

실습 문제

직접 해보기

1. 나를 소개하는 변수 4개 선언하기 난이도 하

이름(string), 나이(int), 키(double), 학생 여부(bool)를 각각 변수로 선언하고, Console.WriteLine으로 한 문장에 출력해보세요.

문자열 보간($"...") 안에서는 {변수명} 형태로 값을 바로 끼워 넣을 수 있어요.
string name = "홍길동"; int age = 24; double height = 178.5; bool isStudent = false; Console.WriteLine($"{name}, {age}살, {height}cm, 학생: {isStudent}");
2. 복사되는 것과 가리키는 것 난이도 중

정수 변수 하나와 값 두 개짜리 배열 하나를 만들고, 각각을 다른 변수에 담은 뒤 담은 쪽만 고쳐보세요. 그리고 원래 변수가 어떻게 되었는지 함께 출력해 차이를 확인해보세요.

한쪽은 값이 복사되고 다른 한쪽은 위치가 복사됩니다. 그래서 담은 쪽만 고쳤는데도 결과가 서로 다르게 나옵니다.
int a = 10; int b = a; b = 99; Console.WriteLine($"값 형식: a={a}, b={b}"); // 값 형식: a=10, b=99 int[] c = { 10, 20 }; int[] d = c; d[0] = 99; Console.WriteLine($"참조 형식: c[0]={c[0]}, d[0]={d[0]}"); // 참조 형식: c[0]=99, d[0]=99
요약
  • 변수는 타입 이름 = 값; 형태로 선언합니다.
  • 값 형식은 담을 때 값이 복사되고, 참조 형식은 위치가 복사되어 둘이 같은 것을 가리킵니다.
  • var는 타입을 없애는 게 아니라, 컴파일러가 대신 추론하게 할 뿐입니다.
  • 돈을 다룰 때는 double 이 아니라 decimal 을 사용합니다.

C# 버전별 변경 이력 에서 각 버전이 무엇을 더했는지 볼 수 있습니다.