C#(2) - 배열, 스코프

MINO·2024년 3월 19일
0

C#

목록 보기
2/7
post-thumbnail

24-03-19
내배캠에서 지원하는 C# 사전 문법 기초 깃북을 정리했다.
내일부터는 Unity 게임 개발 종합반 강의를 시작해야겠다.

배열

제공되는 C# 사전 문법 기초 노션에는 정적 배열에 관한 정보만 있어 동적 배열의 정보도 함께 찾아보았다.

정적 배열

  • 연관된 데이터를 미리 할당된 크기 만큼 저장.
    • C# : new 키워드를 사용하여 배열 선언
// C# - 데이터형식[] 배열명 = new 데이터형식[요소 개수];
string[] game = new string[2];

string[] character;
character = new string[3];

// C++ - 데이터형식 배열명[요소 개수];
string test[5];

동적 배열

  • 크기가 고정적인 정적 배열의 단점을 보완하여 크기를 동적으로 늘릴 수 있음.
    • C# : new 키워드와 ArrayList, List<T> 클래스 사용
    • C# 에서는 가비지 컬렉터 가 메모리 관리를 자동으로 처리해주기 때문에 생성한 객체를 명시적으로 해제할 필요 없음
// C# - ArrayList , List<T>
using System.Collections; // ArrayList
using System.Collections.Generic; // List<T>

ArrayList myList1 = new ArrayList();
myList1.Add(10);
myList1.Add(20);
int val1 = (int) myList1[1];
System.Console.WriteLine(val1); // 20 출력

List<int> myList2 = new List<int>();
myList2.Add(1);
myList2.Add(2);
int val2 = L[1];
System.Console.WriteLine(val2); // 2 출력

// C++ - 포인터명 = new 데이터형식[요소 개수];
int num = 10;
int *pA = new int[num]; // 배열을 동적으로 확보
delete[] pA; // 배열을 동적으로 해제

ArrayList 클래스 

안에 들어가는 모든 요소들이 object 타입으로 취급된다.

  • 박싱(Boxing): 값 타입을 object 타입으로 변환하는 과정
  • 언박싱(Unboxing): object 타입을 다시 원래의 값 타입으로 변환하는 과정

ArrayList는 배열 요소를 읽어 사용할 때 object를 리턴하므로 일반적으로 원하는 타입으로 먼저 캐스팅(Casting)한 후 사용하게 된다.

어떤 타입이든 ArrayList 안에 저장할 수 있다.

int val1 = (int) myList1[1];  // object -> int 형변환

List<T> 클래스 

배열 요소가 T 타입인 동적 배열을 지원

List<T> 클래스는 내부적으로 배열을 가지고 있으며, 동일한 타입의 데이터만 저장
배열의 크기가 부족한 경우, 자동으로 내부 배열의 크기를 두 배로 확장

ArrayList 와 다르게 캐스팅을 할 필요가 없으며, 박싱 / 언박싱의 문제를 발생시키지 않아 성능이 좋고, 코드도 간결하다.

int val2 = myList2[1]; // 형변환 필요 없음

using System.Collections

C# 에서 사용하는 지원하는 자료구조 클래스

  • ArrayList, Queue, Stack, HashTable ...
  • 안에 들어가는 모든 요소들이 object 타입으로 취급
    • 박싱과 언박싱이 발생 -> 많이 사용하면 성능 저하 발생

System.Collections

using System.Collections.Generic

Collections 의 성능 문제로 대신 사용하는 Generic Collections

  • List<T>, Dictionary<T>, Queue<T>, Stack<T> ...
  • 데이터 형식을 일반화하여 사용

System.Collections.Generic

foreach

배열이나 컬렉션의 각 요소를 순회하는 데 사용되는 반복문

C# 에서의 foreach

컬렉션의 각 요소를 순회할 때 사용
읽기 전용 접근 제공

int [] arr = {1,2,3,4,5};

foreach(int number in arr)
{
	Console.WrtieLine(number);
    // number *=2; -> 컬렉션의 요소를 변경하려고 하면 컴파일 에러 발생
}

일반적으로 C#에서 foreach 문을 사용할 때 컬렉션의 요소를 변경할 수 없으므로, 값 변경이 필요할 때는 for 루프를 사용해야 한다.


C++ 에서의 foreach

new 로 할당된 동적 배열은 foreach 문으로 순회할 수 없음
( vector 로 할당한 동적 배열은 가능 )
읽기와 쓰기 접근 모두 가능

vector<int> v = {2,4,6,8,10};

for(int i : v) // 읽기 접근
	cout << i << endl;
    
int arr[] = {1,2,3,4,5};    

for(int& num : arr) // 쓰기 접근
	num *= 2; // 컬렉션의 요소 변경 가능

ref 키워드

C# 에서의 foreach 문은 쓰기에 대한 접근이 불가능하다고 배웠지만, 마이크로소프트 Learn 에서 foreach 문에서 ref 키워드를 통해 쓰기 접근을 하는 코드를 발견했다.

Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
    item = num++;

foreach (ref readonly var item in storage)
    Console.Write($"{item} ");

// Output:
// 0 1 2 3 4 5 6 7 8 9

C# - foreach

  • Span<T> : 메모리 내의 연속된 데이터에 대한 안전한 접근 제공
    • 배열의 일부분을 가리키는 뷰
    • 힙 영역에 메모리를 생성하지 않고도 원본 배열에 대한 참조를 제공
  • stackalloc : 메모리 할당을 위한 C# 키워드
    • 지정된 타입의 배열을 스택 메모리에 생성
    • 빠른 할당과 해제를 가능하게 하며, 가비지 컬렉터의 관리를 받지 않음
  • readonly : 읽기 전용 접근을 위한 C# 키워드
    • 값의 변경 불가능

매개변수 한정자

매개변수 앞에 붙여 특정 기능을 제한하거나 허용하는 키워드

  • 함수의 매개 변수로 사용 시, 매개 변수 앞에 한정자 작성

ref

기본적으로 함수에 인자를 전달할 때, call by value(값 전달)
ref 키워드를 통해 call by reference(참조 전달)

  • 변수를 전달하기 전에 반드시 초기화 해야 한다.
  • 변수가 함수 안에서 변경될 수 있다.
  • 함수 호출 시 ref 키워드 작성
public void Func(ref int n) {...}

int a = 10;
Func(ref a);

int c;
// Func(ref c); -> 초기화 하지 않은 변수는 ref 로 넘길 수 없다.

out

변수를 참조 형태로 전달할 때 사용

  • 변수를 전달하기 전에 변수를 초기화하지 않아도 된다.
  • 함수 안에서 반드시 할당되어야 한다.
  • 함수 호출 시 out 키워드 작성
public void Func(out int n)
{
	n = 10; // 내부에서 반드시 할당되어야 함
}

int num;
Func(out n);

ref 키워드는 메서드 내에서 전달하는 변수를 변경해야할 때
out 키워드는 메서드 내에서 전달하는 변수를 초기화할 때
사용하면 될 것 같다.


in

변수를 참조 형태로 전달할 때 사용

  • 변수를 전달하기 전에 반드시 초기화 해야 한다.
  • 함수 내부에서 값을 수정할 수 없다.
  • 함수 호출 시 in 키워드를 따로 작성하지 않아도 됨
public void Func(in int n) { ... }

int num = 10;
Func(num);

스코프

클래스 안

접근 제한자 O

public class MyClass : MonoBehavior
{
	int x; // 변수 생성
    int y = 10; // 선언 시 초기화
    // x = 10; 변수 선언 후 초기화 X
	// Debug.Log("Logic Code..."); 로직 작성 X
    
    void func() // 함수 작성
    {
    	Debug.Log("Logic Code..."); // 로직 작성
	}
    
    public int z; // 접근 제한자 설정
}

함수 안

접근 제한자 X

void func()
{
	int x; // 변수 생성
    int y = 10;
    if(y != 10) // 로직 생성
    {
    	Debug.Log("y != 10");
	}
}

foreach 문의 예제를 찾다가 Span<T> 와 stackalloc 를 찾아보게 되고, ref 를 공부하다가 in, out 매개변수 한정자에 대해 공부하게 되었다.
꼬리 물기식 공부법 좋은 것 같다.

profile
안녕하세요 게임 개발하는 MINO 입니다.

0개의 댓글