3.1 

int type이 아닌 타입 간 사칙 연산 시 정수형 변환된다.(n1 + n2) 

sum 변수와의 타입이 다른 int형 n1 + n 2 값을 할당하려니 컴파일에러가 발생된다.

이유는 왼쪽 sum의 타입이 오른쪽 변수들의 타입보다 작기 때문이다. 이때는 오른쪽 값의 캐스팅 진행해야한다.

 

C#의 기본 타입

size signed(Dotnet) unsigned
8 bit sbyte(System.Sbyte) byte(System.Byte)
16bit short(System.Int16) ushort(System.UInt16)
32bit int(System.Int32) uint(System.UInt32)
64bit long(System.Int64) ulong(System.UInt64)
128bit NONE(System.Int128) NONE(System.UInt128)

 

실수형 타입

size Type
4 byte float(System.Single)
8 byte double(System.Double)
16 byte decimal(System.Decimal)
반올림 오차가 허용되지 않는 회계 계산에 적합

 

문자형 타입

size Type
유니코드 16bit 문자 char(System.Char)

//ushort가 수를 담기 위한 타입으로 정해져 있으며 char는 문자를 담기 위한 타입으로 약속돼 있다.
유니코드 문자열 string(System.String)

 

닷넷이 지원하는 타입과 C# 타입은 대응된다.

 

타입이 크기 제한에 대한 유형이라고 생각했지만, "소수점이 있는 연산을 할 때 일반적으로 double을 사용하지만 빠른 처리속도가 필요할 시 연산 값이 4바이트 단정도 실수로도 충분하다면 float을 사용할 수 있다" 문구에서 보듯, 타입 크기가 작을 수록 연산속도가 빠르나 보다.

 

gpt 답변

더보기

타입 크기와 연산 속도의 관계

일반적으로 타입 크기가 작을수록 연산 속도가 빠를 수 있지만, 항상 그런 것은 아니다. 몇 가지 고려해야 할 요소가 있다.


🔹 1. float vs. double 연산 속도

일반적으로 float보다 double이 빠름

  • 과거에는 float(4바이트) 연산이 double(8바이트)보다 빠를 수 있었다.
  • 하지만 현대의 CPU는 대부분의 부동소수점 연산을 double(8바이트)로 최적화했기 때문에, 일반적인 연산에서는 float이 double보다 속도가 빠르다고 보기 어렵다.
  • 최신 프로세서는 double 연산을 하드웨어적으로 빠르게 처리하기 때문에, float을 사용하는 것이 성능 향상으로 이어지는 경우는 적다.

예외적인 경우

  • 메모리 대역폭이 중요한 경우: float이 double보다 크기가 작기 때문에, 메모리에서 데이터를 읽거나 저장하는 속도는 더 빠를 수 있음. (하지만 CPU 연산 속도와는 다름)
  • SIMD(벡터 연산) 활용 시: 벡터화된 연산에서는 float을 사용하면 한 번에 더 많은 데이터를 처리할 수 있어 double보다 유리할 수 있음.

🔹 2. 정수형 연산 (int, long) 속도 비교

  • 일반적으로 int(4바이트)와 long(8바이트)의 연산 속도 차이는 크지 않음.
  • 하지만 메모리 접근이 많아지면 int가 더 유리할 수 있음(메모리 사용량 감소).
  • 64비트 CPU에서는 int와 long 모두 최적화되어 있기 때문에 연산 속도 차이는 거의 없음.

🔹 3. 캐시와 메모리 대역폭 영향

  • 작은 데이터 타입(float, int)을 사용하면 캐시 효율이 좋아져 전체 성능이 향상될 수 있음.
  • 대량의 데이터를 처리하는 경우(float 대신 double을 쓰면 메모리를 2배 차지하므로), float이 유리할 수 있음.

🔹 결론

  1. 연산 속도 자체는 float보다 double이 더 빠를 가능성이 높다.
    • 최신 CPU에서는 double이 float과 거의 동일한 속도로 연산됨.
  2. 메모리 대역폭이 중요한 경우(float이 차지하는 메모리가 작을 때)는 float이 유리할 수 있음.
    • 대량의 데이터를 처리할 때 캐시 효율이 올라감.
  3. 정수형(int, long)은 CPU 아키텍처에 따라 속도 차이가 거의 없거나 미미함.
    • 단, long이 메모리를 더 차지하므로 메모리 최적화가 필요하면 int 사용이 유리할 수 있음.

📌 즉, 연산 속도보다 메모리 사용량이 중요한 경우 float이 유리할 수 있지만, CPU 최적화된 연산 속도만 보면 double이 더 빠를 수도 있다. 🚀

 

 

float f = 5.2f;
double d = 10.7;
decimal m = 200.99m;

Console.WriteLine(f);
Console.WriteLine(d);
Console.WriteLine(m);

float의 값은 마지막에 f를, decimal의 경우 소수점 포함 시 m을 붙여야 한다,.

 

escape sequence 표현법: \t, \n, \

Console.Write($"{"a"}\\t\\n");

\t와 \n을 문자(열) 그대로 출력하고자 \를 사용했다.

 

키보드로 입력할 수 없는 유니코드문자(다국어 지원을 위한 문자집합)로 escape sequence 사용

Console.Write($"\u25b6");

출력: ▶

 

 

C#은 정적 타입 언어로 변수나 함수, 클래스, 구조체등에 대한 타입(자료형)을 선언해야 한다.

동적 타입 언어의 경우 자료형을 선언할 필요가 없다.

하지만 C#도 동적 타입 언어의 구문을 수용하였다. (C# 3.0)

 

정적타입언어의 특징은 자료형의 바이트 수를 직접 제어 가능하여 저장 공간을 최적화(절약)할 수 있다.

다만, 최근 기술에 발전으로 PC의 사양이 높아진 가운데 저장 공간이 낭비되도 사양이 뒷받쳐줌에 따라 정적타입의 특징이 무색해졌다.

 

 

* 유니코드(by Chat Gpt)

더보기

유니코드(Unicode)란?

유니코드(Unicode)는 전 세계의 모든 문자를 통합적으로 표현하고 다룰 수 있도록 설계된 문자 인코딩 표준입니다. 기존의 문자 인코딩 방식(예: ASCII, EUC-KR, Shift-JIS 등)은 특정 언어에 종속되거나 한정된 문자 집합만을 지원했지만, 유니코드는 다양한 언어와 기호를 단일한 체계로 다룰 수 있도록 합니다.

유니코드의 주요 목표

  1. 전 세계 모든 문자 표현 가능
    • 한글, 영어, 중국어, 일본어 등 다양한 문자뿐만 아니라 수학 기호, 이모지, 특수 기호까지 포함.
  2. 일관된 문자 코드 할당
    • 같은 문자는 어떤 환경에서도 동일한 코드 값으로 인식되도록 설계.
  3. 다양한 인코딩 형식 지원
    • UTF-8, UTF-16, UTF-32 등의 여러 인코딩 방식을 통해 유연한 데이터 저장과 전송이 가능.

유니코드의 기본 개념

1. 코드 포인트(Code Point)

유니코드는 각 문자에 특정한 번호(코드 포인트, Code Point)를 할당합니다.

  • 코드 포인트는 U+XXXX 형식으로 표현되며, U+0000 ~ U+10FFFF 범위에서 사용됩니다.
  • 예:
    • U+0041 → 영어 대문자 'A'
    • U+AC00 → 한글 '가'
    • U+1F600 → 😀 (이모지)

2. 유니코드 블록(Unicode Blocks)

유니코드는 언어 및 문자 유형에 따라 **여러 개의 블록(block)**으로 나뉩니다.

  • 기본 라틴 문자 (Basic Latin, U+0000 ~ U+007F) → ASCII 문자 포함
  • 한글 음절 (Hangul Syllables, U+AC00 ~ U+D7A3) → 한글 음절 문자 포함
  • 한자 (CJK Unified Ideographs, U+4E00 ~ U+9FFF) → 중국어, 일본어, 한국어 한자 포함
  • 이모지 (Emojis, U+1F600 ~ U+1F64F 등) → 😀, ❤️ 같은 이모지 문자 포함

3. 문자와 글리프(Glyph)의 차이

  • 문자(Character): 의미적인 개념으로, 코드 포인트를 통해 식별됨.
  • 글리프(Glyph): 특정 글꼴에서 문자가 표현되는 모양.
    • 예를 들어, 같은 U+0041 (A)라도 Arial과 Times New Roman 글꼴에서는 다르게 보임.

유니코드 인코딩 방식

유니코드 문자(코드 포인트)를 실제로 컴퓨터가 처리할 수 있도록 바이트 단위로 변환하는 방식유니코드 인코딩이라고 합니다. 대표적인 인코딩 방식으로는 UTF-8, UTF-16, UTF-32가 있습니다.

1. UTF-8

  • 가변 길이 인코딩 (1~4바이트 사용)
  • ASCII 문자(0~127)는 1바이트 그대로 유지 (호환성 우수)
  • 유럽어, 한글, 한자는 2~4바이트 사용
  • 가장 널리 사용되는 인코딩 방식 (웹 및 파일 저장에 최적화)

문자코드 포인트UTF-8 바이트

A U+0041 0x41 (1바이트)
U+AC00 0xEA 0xB0 0x80 (3바이트)
😀 U+1F600 0xF0 0x9F 0x98 0x80 (4바이트)

2. UTF-16

  • 가변 길이 인코딩 (2바이트 또는 4바이트 사용)
  • 대부분의 문자(기본 평면 BMP)는 2바이트로 표현
  • 추가 문자(SMP 이상)는 4바이트로 표현 (서로게이트 페어 사용)
  • Windows 운영체제 및 일부 프로그래밍 언어(Java, C#)에서 사용

문자코드 포인트UTF-16 바이트

A U+0041 0x0041 (2바이트)
U+AC00 0xAC00 (2바이트)
😀 U+1F600 0xD83D 0xDE00 (서로게이트 페어, 4바이트)

3. UTF-32

  • 고정 길이 인코딩 (모든 문자가 4바이트)
  • 단순하지만 비효율적 (메모리 낭비 큼)
  • 주로 시스템 내부 처리 용도로 사용됨

문자코드 포인트UTF-32 바이트

A U+0041 0x00000041 (4바이트)
U+AC00 0x0000AC00 (4바이트)
😀 U+1F600 0x0001F600 (4바이트)

한글과 유니코드

한글은 음절 단위로 유니코드에 할당되어 있으며, 현대 한글 11,172자(U+AC00 ~ U+D7A3)가 포함되어 있습니다.

한글의 유니코드 구조

한글은 초성, 중성, 종성으로 조합되지만, 유니코드에서는 완성형으로 인코딩됩니다.

  • 예) 한 (U+D55C) → 초성(ㅎ), 중성(ㅏ), 종성(ㄴ) 조합

이와 별도로, 초성/중성/종성을 분리하여 표현하는 한글 자모 영역(U+1100 ~ U+11FF) 도 존재합니다.


유니코드의 장점과 단점

장점

  1. 전 세계 문자 통합 지원 → 다국어 지원이 쉬움.
  2. 일관된 코드 체계 → 시스템 간 문자 변환 오류 최소화.
  3. ASCII와 호환 (UTF-8 기준) → 기존 ASCII 기반 시스템과 호환 유지.

단점

  1. 파일 크기 증가 → UTF-8은 일부 문자에서 바이트 수 증가 (한글 3바이트).
  2. 복잡한 인코딩 구조 → 가변 길이 인코딩(UTF-8, UTF-16)은 인덱싱이 어렵고 처리 비용이 증가.

유니코드와 현실적인 적용

현재 대부분의 시스템과 웹사이트는 UTF-8을 기본 인코딩으로 사용합니다.

  • 웹 표준: HTML, JSON, XML 등 대부분의 웹 기술이 UTF-8을 기본으로 채택.
  • 프로그래밍 언어: Python, JavaScript, Go 등은 UTF-8을 기본 문자 인코딩으로 사용.
  • 운영체제: Windows는 내부적으로 UTF-16 사용, Linux 및 macOS는 UTF-8 사용.

결론

유니코드는 전 세계 모든 문자를 하나의 통합된 체계로 표현하기 위한 표준이며, UTF-8, UTF-16, UTF-32 같은 다양한 인코딩 방식을 통해 사용됩니다. 현재 UTF-8이 가장 널리 사용되며, 웹 및 현대 소프트웨어 개발에서 필수적인 문자 인코딩 방식입니다.

 

 

## 3.2 형변환

명시적 형변환: 개발자가 형 변환 코드를 지정하지 않고 컴파일러나 인터프리터가 자동으로 형 변환을 수행.


형변환 연산자(cast operator): 명시적 형변환 시 캐스팅 타입의 가로 형태 '(' ')'

short b = 258;
byte s = (byte)b;  // ( ) is cast operator
Console.WriteLine(s);

 

 

암시적 형변화: 개발자가 명시적으로 형 변환 코드를 지정.

▶ 작은 타입 -> 큰 타입 방향으로 변환. 

short s = 10;
int i = s; // s 타입 : short -> int 자동 변환
long l = i; // i 타입 : int -> long 자동 변환

 

 

3.3.1 예약어, 키워드 : 약속된 명칭 eg. byte , void등 문법 표현을 위해 미리 예약된 언어.

3.3.2 식별자: 사용자가 지정한 단어. eg. 함수명, 변수명, namespace 등.

@ + 예약어 의 경우 식별자로 인식.

string @string = "aaa";
Console.WriteLine(@string);

 

3.3.3 리터럴: Literal == '소스코드에 포함된 값' 즉 오른쪽 값이 Literal

int a = 5;
char b = 'b';
string asd = "ASD";

//5, 'b', "ASD"  모두 리터럴

 

3.3.4 변수 : 값 형식의 변수, 참조 형식의 변수

 

3.3.4.1 스택과 힙 저장소

닷넷에서 CLR은 프로그램이 직접 사용 할 힙을 관리한다.

C# 컴파일러는 스택 영역 내 특정 메모리 영역을 자동 할당 및 해제해준다. 

힙 영역에 메모리 할당을  한 부분은 C/C++과는 달리 직접 해제 하지 않고 가비지 컬렉터를 통해 자동으로 해제해준다. (5.4절 더 자세히...)

 

 

3.3.4.2/3

값 형식을 가리키는 변수: 값 자체가 스택 영역에 할당되고, 변수는 그 메모리를 가리키는 프로그램 내 식별자.

종류: sbyte, byte, bool, decimal, short, ushort, char, int, uint, long, ulong, float, double...

->값을 stack에 저장.

 

참조 형식을 가리키는 변수:

종류: string, 클래스, 배열, object ... 

->값을 heap에 저장. 

string t = "test";

값 test를 stack 영역에 저장 후 heap 영역에 메모리를 할당하여 참조 형식의 t 변수가 저장 된 stack의 값 "test"를 할당된 heap 영역의 메모리 주소를 가리킨다.

 

** 변수 선언 자체만으로 스택 내의 메모리 영역을 사용할 수 있게 C# 컴파일러에 의해 자동 할당 및 해제된다. 그래서 개발자 입장에서는 스택의 메모리 할당 및 해제를 직접 하지 않는다. 반면 힙 영역에 메모리 할당은 개발자가 명시적으로 요청함에 따라 메모리 해제과정이 필요하다.

해제 과정은 네이티브 환경과 관리환경이 구분된다.

개발자가 직접 할당과 해제하는 경우를 네이티브 환경(C/C++ 등 사용)

개발자가 오직 객체 할당만 하고 해제는 관리환경 내의 특정 구성요소(가비지 수집기)가 담당하는 것을 관리 환경이라 한다.

 

5.4 절 힙과 스택에 대해 더 자세히 설명.

3.3.4.4 기본값

int a; // 0
bool b; // false
string c; //null

 

3.3.4.5 상수

상수 식: 컴파일 할 때 값이 결정되는 수식,  right 값

상수: left 변수

 

3.4 배열

string [] names = new name[100];
int [] products = new int[5];

new 예약어는 힙 영역에 메모리 할당을 하는 역할.

 

배열 초기화 방식

1. int[] products = new int[5] {1,2,3,4,5};  // 배열의 요소 개수 지정
2. int[] products = new int[] {1,2,3,4,5};   // 배열의 요소 개수 미지정

배열의 요소 개수 미지정 시 컴파일러가 자동으로 원소의 수 만큼 자동으로 배열의 크기를 5로 지정한다.

 

string 타입을 배열처럼 다룰 수 있었던 점은 인덱서를 구현했기 때문이다.

 

배열의 초기 값은 값 타입이라면 0, 참조 타입이라면 null값이다.

int [] valArr = new int[60];
valArr[0] = 50;
Console.WriteLine(valArr[0]);  // 50 

valArr = new int[120];
Console.WriteLine(valArr[0]); // 0

 

3.4.1 다차원 배열

# 2차원 배열
int[,] arr2 = new int[10, 5]; // 10 * 5 * 4byte = 200 byte

# 3차원 배열
short[,,] arr3 = new short[8,3,10];  // 8 * 3 * 10 * 2 byte = 480 byte

3차원 배열의 경우 [a, b, c] 에서  a는 z , b는 row, c는 col

 

#2차원 배열 초기화
int[,] arr2 = new int[2, 3]
{
    {1, 2, 3 },
    {4, 5, 6 },
};

#3차원 배열 초기화
short[,,] arr3 = new short[,,]
{
    {
        {1, 2, 3 },
        {4, 5, 6 },
        {5, 6, 7},
    },
    {
        {10,11,12},
        {12,13,14},
        {13,14,15},
    }
};

 

3.4.2 가변배열

int[][] arr = new int[3][];
arr[0] = new int[5];
arr[1] = new int[3];
arr[2] = new int[2];

# 결과:
arr[0] = arr[0][0] arr[0][1] arr[0][2] arr[0][3] arr[0][4]
arr[1] = arr[1][0] arr[1][1] arr[1][2]
arr[2] = arr[2][0] arr[2][1]

배열의 메모리를 최적화하기 위하여 사용되는 가변 배열. 다만, 가독성을 위해서 일반 배열이 실무적으로 자주 사용.

 

3.5.1 논리 연산자

좌측 피연산자 우측 피연산자 AND(&&) 연산 결과
true true true
true false false
false true false
false false false
좌측 피연산자 우측 피연산자 OR(||) 연산 결과
true true true
true false true
false true true
false false false
좌측 피연산자 우측 피연산자 XOR(^) 연산 결과
true true false
true false true
false true true
false false false
우측 피연산자 NOT(!) 연산 결과
true false
false true

 

 

3.5.1.3 switch 문 

조건 판단의 기준이 되는 식이 상수.

switch (인스턴스)
{
    case 상수식1:
        구문;
        break;
    case 상수식 n:
        구문;
        break;
    default:
        구문;
        break;
}

 

TODO

p75 3.5.2 반복문

 

증감연산자: ++, --

1) 후위 표기법: 피연산자 값이 평가 된 후 값 증가/감소
2) 전위 표기법: 피연산자 값을 증가/감소 시킨 후 식을 평가
eg 1.

int n = 50;
Console.WriteLine(n++); // 50
n = 50;
Console.WriteLine(++n); //51

n = 50;
int rt = n++;
Console.WriteLine(rt);

n = 50;
rt = ++n;
Console.WriteLine(rt);

 

eg 2.

int n = 50;
int x = 100;

if( x> 10 || n++ > 10)
{

}
Console.WriteLine(n);

여기서 n 은 x > 10 의 조건이  true 일 시 증감되지 않기에, 이러한 방식을 의도한게 아니면, 기피하자.

int n = 50;
int x = 100;

if( x> 10 || n> 10)
{

}
n++;
Console.WriteLine(n);

위와 같이 코드를 수정한다.

 

복합 대입 연산자

+=, -= , *= , /=, %=

 

단순 대입 연산자로는 '=' 이 있고 그 밖의 모든 대입 연산자는 복합 대입 연산자에 속한다.

 

for문

int n = 5;
int idx = 0;
for(; idx < n; ++idx)
{
    Console.WriteLine(idx);
} // 0,1,2,3,4

idx = 0;
for (; idx < n; idx++)
{
    Console.WriteLine(idx);
} // 0,1,2,3,4
idx = 0;
for (; ;idx++){
    if(idx > 4) break;
    Console.WriteLine(idx);
} // 0,1,2,3,4

for(; ; )
{
    if(idx > 4) break;
    idx++;
    Console.WriteLine(idx);
} // 0,1,2,3,4

 

 

3.5.2.3 중첩루프 == 이중루프  O(N^2)

 

3.5.2.4 foreach 문

foreach (표현식요소의 자료형 변수명 in 표현식)
    구문;
또는
foreach ( 표현식 요소의 자료형 변수명 in 표현식) 구문;

foreach문은 컬렉션이나 배열을 순회(iterate)할 때 사용하는 반복문으로 for문과 달리 인덱스를 직접 다루지 않고, 컬렉션의 요소를 하나씩 가져와 반복하는 방식이다. 

 

eg.

int[] arr = new int[] { 1, 2, 3, 7, 8, 9 };

foreach (int elem in arr)
{
    Console.Write(elem + ", ");
} // 1, 2, 3, 7, 8, 9,

일반적으로 foreach문이 for문 보다 간결하기에 더 많이 사용.

 

3.5.2.5  while 문 : 조건식만 있는 반복문

do -while의 필요성은 거의 없다.(가독성, 조건을 따지지 않고 첫번째는 무조건 실행하기에)

일반적인 루프는 대부분 for 또는 while 문으로 처리할 수 있다. do-while이 필요한 경우는 아래처럼 사용자의 입력을 받을 때처럼 최소 한 번은 실행해야 하는 경우 정도다.

가독성 높은 반복문을 사용하는 것을 권고한다.

 

3.5.3 점프문(jump statements)

eg. break, continue, goto, return, throw.

 

break문은 반복문에서 루프를 벗어나게 하고 continue문은 이후의 반복 구문 실행 생략과 동시에 조건식 평가로 실행을 옮기면서 반복을 계속한다.

또한 break와 continue는 가독성 높이고자 들여쓰기 블록을 줄이는 역할도 한다.

int n = 0;
int sum = 0;
while (n++ <= 1000)
{
    if (n % 2 != 0) continue;
    if (n % 3 != 0) continue;
    if (sum >= 100) break;
    sum += n;
}
Console.WriteLine(sum);

 

goto

int n = 0;
int sum = 0;
LOOP:
  n++;
  if (n > 1000)
  {
    goto LOOPEXIT;
  }
  if (n % 2 != 0) goto LOOP;
  sum += n;
  goto LOOP;
LOOPEXIT:
Console.WriteLine(sum);

goto문(with 레이블문 ':'  이용하며 레이블문은 관례상 대문자로 만듦. )과 if문으로 충분히 반복문 구현 가능하나 가독성이 떨어진다.

 

가독성이 높아지는 경우는 중첩 루프를 빠져나오는 경우다.

bool isExit = false;
for(int y = 0; y < 5; ++y)
{
    for(int x = 0; x < 3; ++x)
    {
        isExit = (y == 2 && x == 1);
        if (isExit is true) break;
    }
    if(isExit is true) break;
}

이중 루프에서 isExit를 활용해 루프를 빠져나왔지만 goto는 다음과 같이 바로 조건문을 두번 사용할 필요 없이 빠져나올 수 있다.

for(int y = 0; y < 5; ++y)
{
    for(int x = 0; x < 3; ++x)
    {
        if (y == 2 && x == 1) goto LOOP_EXIT;
    }
 
}
LOOP_EXIT:;

 

https://euler.synap.co.kr/problem=1

 

1번 문제

1000보다 작은 자연수 중에서 3 또는 5의 배수를 모두 더하면?

euler.synap.co.kr

 

int sum = 0;
int idx = 1;

for (; idx < 1000; ++idx)
{
    if (idx % 3 == 0 || idx % 5 == 0) sum += idx;
}
Console.WriteLine(idx);

 

 

예약어 sbyte, byte, short, ushort, int, uint, long, ulong
float, double, decimal
char, string
bool
if, else
switch, case, break, default
for, foreach
while, do
continue, goto
new, null
연산자 관계 연산자: >, <, >=, <=, ==, !=
조건(삼항) 연산자: ?:
논리 연산자: &&, ||, !, ^
대입 연산자: =, +=, -=, *=, /=, %=
증감 연산자: ++, --
문장 부호 배열을 나타내는 대괄호: []
블록을 나타내는 중괄호: {}
구문의 끝을 나타내는 ';'

 

 

 

가장 중요한 부분 stack과 힙

다시 살펴보자 !

3.3.4.1 두 가지 저장소: 스택과 힙.

스택: 자료구조의 스택과 이름이 같으며, 동작방식은 같지만 OS가 만든 특별한 저장소 지칭.

힙: 자료구조의 힙과 이름이 같으며, 닷넷런타임이 관리하는 특별한 저장소 지칭.

 

윈도우 프로그램은 기본적으로 하나의 스레드를 갖으며 개별 스레드마다 전용으로 사용할 수 있는 저장소가 메모리에 할당된다. 그 영역을 스택이라 한다. 

힙은 프로그램에서 필요에 의해 메모리를 사용하겠다고 요청했을 때 사용할 수 있는 저장소며 닷넷에서는 CLR이 직접 프로그램에서 사용될 힙을 관리한다.

 

메모리를 할당하고 해제하지 않으면 일정 시간 후 유한한 자원인 메모리의 영역에서 더 이상 사용할 수 있는 용량이 부족하여 프로그램의 실행과정 상에서 오류가 발생한다. 그래서 할당된 메모리를 해제해주어야 한다.

개발자 입장에서 스택은 변수를 선언 하는 것 자체만으로 스택 내의 특정 메모리 영역을 사용할 수 있게 C# 컴파일러에 의해 자동 할당 및 해제된다. 

반면 힙의 경우 개발자가 명시적으로 요청한 것이기에 개발자가 직접 해제도 해야하지만, C#에서는 가비지 수집기를 통해 자동으로 해제해준다.(관리 환경)

다만 네이티브환경(C/C++)처럼 직접 해제 해주는 경우도 있다.

 

변수는 값형식과 참조형식이 있는데 값을 스택에 저장하면 값형식, 힙에 저장하면 참조형식이다.

값 형식은 그 변수의 타입에 해당하는 값을 스택 영역에 저장하지만, 참조형식을 위한 변수는 그 값을 담기 위해 별도로 힙 영역의 메모리를 할당하고 스택의 변수 값은 다시 힙의 데이터 주소를 가리키게 된다.

 

참조 형식 변수는 기본 값으로 숫자 0이아닌 null 예약어가 있다.

값 형식 변수는 기본 값이 0이다.

만약 "aaa" 값이 있으면 힙영역에 할당된 "aaa"값의 힙영역 주소값이 t의 값에 들어간다.(t주소 참조)

p54, p55를 문제로 다시 개념을 다져봐라.

+ Recent posts