본문 바로가기
Program Language/C#

Part1. C# 첫발 내딛기(27. 값 형식과 참조 형식)

by 토담이아빠 2023. 1. 22.

값 형식과 참조 형식

 

C#자료형은 값 형식과 참조 형식으로 나뉩니다. 이 둘의 차이는 데이터를 스택에 저장하느냐 아니면 힙에 저장하느냐에 따라 나뉩니다. 이번 포스팅에서는 각각의 자료형에 대한 특징과 사용법에 대해서 정리했습니다.


값 형식

 

값 형식은 변수가 실제 데이터 값을 저장하는 형식입니다. 값 형식을 갖는 자료형에는 c#의 기본 자료형과 열거형, 구조체가 있습니다. 이들 자료형들에 대한 데이터는 기본적으로 스택에 저장합니다. 다음은 값 형식에 대한 자료형들을 보여줍니다.


C# 값 형식 기본 C#형식(int, double, char, bool, float 등), struct, enum

값 형식을 함수의 인자로 전달할 때 내부에서 변수값을 변경해도 원본의 변수값은 변하지 않습니다. 이러한 특징은 다음 예제롤 통해 확인할 수 있습니다.


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace valueAndReference
{
  
    internal class Program
    {
        public static void TestVaueType(int a)
        {
            a += 10;
        }

        static void Main(string[] args)
        {
            int value = 20;
            Console.WriteLine(value);

            TestVaueType(value); // value 원본값은 변하지 않는다.
            Console.WriteLine(value);
  
        }
    }
}

결과

20
20

참조 형식

 

참조 형식은 변수가 값이 저장되어 있는 곳의 위치를 저장하는 형식입니다. 이것을 참조(reference)라고도 부릅니다. c++에서의 참조와 기능적으로 유사합니다. c#에서 참조 형식을 갖는 자료형은 다음과 같습니다.


C# 참조 형식 object, string, dynamic, class, interface, delegate, 배열

string을 제외한 위 자료형들을 함수의 인자로 전달할 때 함수 내부에서 변수값이 수정된다면 원본의 값도 수정이 됩니다. 


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace valueAndReference
{
  
    internal class Program
    {
        public static void TestRefType(int[] array)
        {
            array[0] = 1111;
        }

        static void Main(string[] args)
        {
            int[] arr = { 10, 20, 30, 40 };
            Console.WriteLine(arr[0]);

            TestRefType(arr); // value 원본 값이 변한다.
            Console.WriteLine(arr[0]);
  
        }
    }
}

결과

10
1111

ref 키워드

 

값 형식의 자료형도 참조로 전달할 수 있습니다. 이때 사용하는 것이 ref 키워드입니다. 선언하는 곳과 사용하는 곳에 ref 키워드를 붙여야 합니다. 다음은 첫 번째 예제를 이용하여 ref키워드를 사용하는 방법을 보여줍니다.


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace valueAndReference
{

    internal class Program
    {
        public static void TestVaueType(ref int a)
        {
            a += 10;
        }

        static void Main(string[] args)
        {
            int value = 20;
            Console.WriteLine(value);

            TestVaueType(ref value); // value 원본값이 변경됩니다.
            Console.WriteLine(value);
        }
    }
}

결과

20
30

값 형식처럼 행동하는 String

 

여기서 한 가지 더 언급할 것이 있습니다. 바로 string타입입니다. string은 분명 참조로 구분됩니다. 왜냐 하면 문자열 생성 시 힙에 생성을 하기 때문입니다. 하지만 string의 행동을 보면 마치 값 형식처럼 행동합니다. 그래서 그냥 string 타입을 함수의 인자로 전달하면 내부에서 수정 시 원본값이 변하지 않습니다. 참조로 쓰고 싶으면 값 형식처럼 ref 키워드를 써야 합니다. string의 이러한 성질은 불변성(immutable) 성에서  기인합니다. 한번 만들면 값을 변경할 수 없기 때문에 string 객체가 변경될 때마다 새로운 힙 영역에 객체를 만듭니다. 이것은 마치 복사본이 생성되는 값 형식처럼 보이게 만드는 원인이 됩니다. 

 

다음은 string에 대한 값 형식과 참조형식을 보여주는 예제입니다.


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Runtime.Remoting.Channels;
using System.Text;
using System.Threading.Tasks;

namespace valueAndReference
{

    internal class Program
    {
        public static void TestVaueString(string s)
        {
            s = "String is value type!";
        }
        public static void TestRefString(ref string s)
        {
            s = "String is ref type!";
        }


        static void Main(string[] args)
        {
            string str = "What type is String?";
            Console.WriteLine(str);

            TestVaueString(str);
            Console.WriteLine(str);

            TestRefString(ref str);
            Console.WriteLine(str);
        }
    }
}

결과

What type is String?
What type is String?
String is ref type!

[참고]

1. "초보자를 위한 C# 200제(2판)" / 저자 : 강병익

2. C# 교과서 / 박용준 지음

3. microsoft c# 메뉴얼 : https://learn.microsoft.com/ko-kr/dotnet/csharp/

댓글