상세 컨텐츠

본문 제목

[C# 이해하기] 값형식(Value Type)과 참조 형식(Reference Type)

개발기록/Computer Science

by 도리(Dory) 2026. 1. 3. 10:36

본문

 

 

C#에서 변수를 만들 때, 우리는 보통 “변수에 값이 들어간다”고 생각합니다.

그런데 자료형에 따라 변수 안에 들어가는 것이 두 가지로 갈립니다.

 

  • 값 형식(Value Type): 변수에 데이터 그 자체가 들어간다
  • 참조 형식(Reference Type): 변수에 **데이터가 있는 곳을 가리키는 정보(참조)**가 들어간다

 

이 차이는 단순 개념이 아니라, 실제 코드에서 대입했을 때, 수정했을 때, 함수에 전달했을 때 동작을 완전히 바꿉니다.

 

 

ValueType vs ReferenceType

 

 


1) “복사되는 게 다르다”

 

 

값 형식: 대입하면 “내용”이 복사된다

int a = 10;
int b = a;  // a의 값(10)이 b로 복사됨
b = 20;

Console.WriteLine(a); // 10
Console.WriteLine(b); // 20

 

b를 바꿔도 a는 그대로입니다.

왜냐하면 처음 대입할 때부터 서로 다른 값을 가지고 있기 때문입니다.

 

 

 

참조 형식: 대입하면 “주소표(참조)”가 복사된다

int[] arr1 = { 1, 2, 3 };
int[] arr2 = arr1; // arr1이 가리키는 "같은 배열"을 arr2도 가리킴

arr2[0] = 999;

Console.WriteLine(arr1[0]); // 999
Console.WriteLine(arr2[0]); // 999

 

arr2를 수정했는데 arr1도 바뀐 것처럼 보입니다.

정확히는 arr1arr2같은 배열(같은 객체)을 공유하고 있기 때문입니다.

 

 


2) “변수 = 상자” 비유로 이해하기

 

 

  • 값 형식 변수: 상자 안에 물건 자체가 들어있음
  • 참조 형식 변수: 상자 안에 물건이 있는 창고 주소가 적힌 쪽지가 들어있음

 

그래서 참조 형식은 상자를 복사해도 “쪽지”만 복사되고, 창고(객체)는 그대로 하나라서 함께 영향을 받습니다.

 


 

3) 대표적인 값 형식 / 참조 형식

 

 

값 형식(Value Type) 

  • int, float, double, bool, char
  • struct (구조체)
  • enum

 

 

참조 형식(Reference Type) 

  • class로 만든 타입
  • string
  • 배열(int[], char[] 등)
  • List<T>, Dictionary<TKey, TValue> 같은 컬렉션

 

여기서 가장 많이 헷갈리는 게 string입니다.

string은 생김새는 값처럼 보이지만, 분류는 참조 형식입니다.

 


4) “참조 형식인데 왜 string은 안전해 보일까?”

 

배열이나 List는 수정이 가능합니다(“mutable”).

하지만 string불변(immutable) 입니다.

 

string s1 = "hi";
string s2 = s1;
s2 = "bye";

 

 

이때 s2를 바꾼 게 아니라, s2새 문자열을 가리키게 된 것입니다.

그래서 “참조 형식인데도 값 형식처럼” 느껴질 수 있습니다.

 

핵심만 정리하면:

 

  • string참조 형식
  • 다만 문자열 내용 자체를 바꾸는 방식이 아니라 새 문자열을 만든다(불변)
  • 그래서 공유로 인한 사고가 상대적으로 덜 보인다

 


 

5) 함수에 전달될 때(매개변수)도 핵심은 “무엇이 복사되나”

 

C#의 기본 전달 방식은 값 전달(call by value) 입니다.

여기서 중요한 포인트는 “값 전달”이 항상 값 형식만 의미하는 게 아니라는 점입니다.

 

  • 값 형식을 전달하면: 데이터 자체가 복사
  • 참조 형식을 전달하면: 참조(주소표)가 복사

 

즉, 참조 형식도 기본은 “값 전달”인데, 그 값이 ‘참조’인 것입니다.

 

void ChangeFirst(int[] a)
{
    a[0] = 777; // 배열 내용 수정 (공유된 객체에 반영)
}

int[] x = { 1, 2, 3 };
ChangeFirst(x);
Console.WriteLine(x[0]); // 777

 

 

 


6) 가장 중요한 실전 결론 3가지

  1. 값 형식은 복사해도 독립적이라 예측이 쉽다.
  2. 참조 형식은 “공유”가 기본이어서, 한쪽 수정이 다른 쪽에 영향을 줄 수 있다.
  3. “내가 지금 바꾸는 게 변수 자체인지, 변수 너머의 객체인지”를 구분하면 실수가 줄어든다.

 

 

관련글 더보기