Learning
When: 1학년 7월 23일
How:
전 글에서 이 내용에 대해 쓰긴 했지만, 게임 마이스터고에 와서 성장폭도 빠르고, 글의 질도 늘고 있기 때문에 조금 더 자세히 쓸 필요가 있다고 생각하여 다시 다루게 되었습니다. (전 글은 여기에 있는데 초반에 쓴 글이라 그런지 너무 별로...)
Understanding:
- 값 형식 : 값 형식은 값이 스택에 저장되는 형식입니다. 스택은 간단히 설명하면 정보를 저장하는 공간인데, 정보를 저장하는 공간이 있으면, 그 공간들을 전부 가지고 있는 커다란 공간도 있겠죠? 여기서 프링글스로 예를 들 것인데, 프링글스 통을 커다란 공간이라고 하면, 그 커다란 공간을 "스택", 프링글스 하나를 "스택 슬롯"이라고 부릅니다. 프링글스는 가장 마지막에 넣은 과자를 맨 처음으로 먹게 되는데, 이것을 후입선출(LIFO (Last In First Out))이라고 부릅니다. 방금 말한 LIFO가 중요한데, 순서대로 값이 쌓인다고 하면, 그 값만의 번호가 생긴다는 것이 됩니다. 즉 이 슬롯이 몇 번째에 있는지만 알면 되기 때문에 따로 슬롯에 이름이나 주소 같은 것이 필요가 없습니다.(필요가 없다고 할 수도 있고 이름이나 주소 같은 것을 슬롯의 번호(이 값은 아래에서 8번째에 있어! 이런 느낌)로 대체했다고도 할 수 있겠네요) 방금은 스택에 대해 최대한 쉽게 설명한 것이고, 사실 이 글에서 중요한 부분은 아닙니다. 스택의 슬롯에는 int나 float 등의 "값"이 저장된다는 것만 알고 계시면 됩니다.
int a = 10; 라는 코드가 있으면 스택에 10이라는 값을 가진 슬롯이 위에서 아래로 툭 떨어진다고 생각하시면 됩니다. (하나씩 차곡차곡 쌓이기 때문에 그 값을 찾을 때는 몇 번째에 있는지에 대한 정보만 있으면 됩니다.) - 참조 형식 : 참조 형식은 주소가 스택에, 값이 힙에 저장되는 형식입니다. 일단 스택은 방금 설명했지만 힙은 설명하지 않았는데, 힙도 값을 저장하는 공간이지만 슬롯이라는 개념이 딱히 없고, 값과 주소가 있습니다. 주소를 통해 값에 접근할 수 있고, 그 주소는 스택에 저장됩니다. 그러니까 스택에 값이 저장되고, 변수로 접근하면 값 형식은 바로 값에 접근할 수 있지만 참조 형식은 주소가 값이기 때문에 그 주소를 통해서 힙에 있는 값을 참조하는 개념입니다. 이렇게 되면 속도는 느려지지만, 힙은 스택에 비해 값을 다루는 것에 자유롭습니다. 크기가 타입에 의해 한번 정해지면 그대로 바꿀 수 없는 스택과 다르게 힙은 크기가 가변적이고, 함수가 끝나면 즉각적으로 사라지는 스택과 다르게 힙은 풀링 등으로 유지시킬 수 있습니다. 그리고 결정적인 차이는 참조 형식은 이름 그대로 참조를 하여 값에 접근하기 때문에 만약 a = b; 이렇게 복사한다고 하면 값이 복사되는 것이 아니라 주소가 복사됩니다. (a 자체는 형식이 참조 형식이든 값 형식이든 스택에 있는 값을 뜻합니다. 그렇기 때문에 a = b; 에서 둘 다 참조 형식이라면 이 문장만 보면 힙에는 아무런 영향도 없고 a의 스택 슬롯에 저장되어 있던 주소가 b의 스택 슬롯에 저장되어 있던 주소로 바뀌어서 a와 b가 같은 주소를 갖게 되는 것이고, 주소가 같으면 참조하고 있는 객체도 같아지는 것입니다.) 값이 복사되는 것과 주소가 복사되는 것의 차이는 값이 복사 되면 값이 2개가 되는 것이고, 둘 중 하나의 값을 건드려도 다른 하나의 값에는 영향이 가지 않지만, 주소가 복사되는 것은 값은 하나이고 주소가 2개가 되는 것이기 때문에 둘 중 하나의 주소를 통하여 값을 건드리면 나머지 하나로 접근 했을 때 다른 주소로 건드린 흔적이 남는다는 것입니다.
int a = 10;
int b = a;
b = 5;
Console.WriteLine(a); // 10 출력됨. (b를 바꾼다고 해도 a가 바뀌진 않습니다. = 값이 2개)
Car car1 = new Car();
car1.name = "람보르기니";
Car car2 = new Car();
car2 = car1;
car2.name = "롤스로이스";
Console.WriteLine(car1.name); // 롤스로이스 출력됨. (car2에서 name을 바꾸면 car1의 name도 바뀝니다.
// = 값이 하나인데 2개의 변수에서 참조 중)
- 그 외 차이점
| 차이점 | 값 형식 | 참조 형식 |
| 삭제 | 메서드가 끝나면 데이터가 바로바로 삭제됩니다. | 위의 코드의 Car car2 = new Car(); 에서 생성된 객체는 car2가 car1의 객체를 참조하게 된 순간부터 접근 할 수 없게 되었습니다. 이런 객체들을 가비지 컬렉터가 알아서 삭제해줍니다. |
| 인수 | 메서드에 인수로 넣어도 값이 복사되어 메서드 안에서 값을 바꿔도 인수로 전달한 변수의 값은 변하지 않습니다. 여기서 변수의 값도 바꾸고 싶을 때 ref와 out, in 키워드를 사용합니다. | 인수로 전달했을 때 스택에 있는 값이 복사되는 것은 값 형식과 똑같지만, 주소가 복사되기 때문에 메서드 안에서 값을 바꾸면 인수로 전달한 변수의 값도 바뀝니다. |
Result: 참조 형식과 값 형식은 특정한 상황이 아니면 차이점을 구별하기 쉽지 않지만, 잘 보면 값이 저장되는 방식이나 삭제되는 방식이 완전히 다르기 때문에 차이점을 잘 알고 있는 사람이 짜는 코드와 모르는 사람이 짜는 코드는 큰 차이가 날 수 있습니다.
'C#' 카테고리의 다른 글
| [C#] 트리(tree) 자료 구조 (3) | 2025.07.25 |
|---|---|
| [C#] string 메서드 (0) | 2025.07.24 |
| [C#] partial 키워드 (0) | 2025.07.22 |
| [C#] params 키워드 (0) | 2025.07.19 |
| [C#] in 키워드 (0) | 2025.07.18 |