배열(Array): 동일한 타입의 여러 데이터를 하나의 변수로 묶어 관리할 수 있는 자료 구조. 고정된 크기를 가지며, 순차적으로 저장된 데이터에 인덱스를 통해 접근할 수 있음.
특징
- 동일한 데이터 타입: 배열은 하나의 데이터 타입만 저장할 수 있어, 타입 안전성을 유지할 수 있음.
- 고정된 크기: 배열의 크기는 초기화 시점에 고정되며, 이후에는 변경할 수 없음.
- 인덱스를 통한 접근: 배열 요소는 0부터 시작하는 인덱스를 통해 개별적으로 접근할 수 있음.
- 연속된 메모리: 배열 요소는 메모리에 연속적으로 저장되어, 데이터 접근 속도가 빠름.
배열의 선언과 초기화: 타입 뒤에 대괄호([])를 추가하여 선언하며, 초기화는 중괄호({})를 사용하거나 new 키워드를 사용하여 할 수 있음.
// 정수형 배열 선언과 초기화
int[] numbers = { 1, 2, 3, 4, 5 };
// 또는 new 키워드 사용
int[] scores = new int[5]; // 크기가 5인 배열 생성, 기본값 0으로 초기화
scores[0] = 10; // 첫 번째 요소에 값 설정
scores[1] = 20;
배열 요소 접근과 수정: 인덕스를 통해 접근하며, 인덕스를 통해 값을 수정할 수도 있음.
int[] numbers = { 1, 2, 3, 4, 5 };
// 배열 요소 접근
Console.WriteLine(numbers[0]); // 출력: 1
Console.WriteLine(numbers[2]); // 출력: 3
// 배열 요소 수정
numbers[2] = 10;
Console.WriteLine(numbers[2]); // 출력: 10
배열의 길이 확인: Length 속성을 사용하여 확인할 수 있음.
int[] numbers = { 1, 2, 3, 4, 5 };
Console.WriteLine(numbers.Length); // 출력: 5
다차원 배열: 배열은 2차원 이상의 다차원 배열로 선언할 수 있음. 다차원 배열은 행과 열로 이루어지며, 2차원 배열은 주로 테이블 형태의 데이터를 저장할 때 유용함.
// 2차원 배열 선언 및 초기화
int[,] matrix = { { 1, 2 }, { 3, 4 }, { 5, 6 } };
// 요소 접근
Console.WriteLine(matrix[0, 0]); // 출력: 1
Console.WriteLine(matrix[2, 1]); // 출력: 6
장점과 단점
- 빠른 데이터 접근: 배열 요소는 인덱스를 통해 빠르게 접근할 수 있음.
- 메모리 효율성: 배열은 메모리에 연속적으로 저장되므로, 데이터 접근과 관리를 효율적으로 수행할 수 있음.
- 반복문을 통한 처리 용이: 배열은 반복문을 통해 모든 요소에 쉽게 접근하고 처리할 수 있어 유용함.
- 고정된 크기: 배열의 크기는 초기화 시점에 고정되며, 이후에는 변경 불가.
- 동일한 타입만 저장: 배열은 동일한 타입의 데이터만 저장할 수 있어, 다양한 타입을 한 배열에 저장하기 어려움.
- 삽입과 삭제의 비효율성: 배열 중간에 요소를 삽입하거나 삭제하는 경우, 요소들을 이동해야하므로 성능이 저하될 수 있음.
System.Array: C#에서 모든 배열의 기본 클래스, 배열을 관리하고 조작할 수 있는 여러 메소드와 속성을 제공하는 클래스.
특징
- 모든 배열의 기본 클래스: System.Array는 모든 배열이 상속하는 클래스. 배열 생성할때마다 이 클래스의 기본 메소드와 속성 사용 가능.
- 배열 조작 기능 제공: 정렬, 검색, 복사, 초기화 등의 기능을 제공함.
- 정적 메소드로 사용: 대부분의 기능은 System.Array 클래스의정적 메소드를 통해 바로 호출할 수 있으며, 특정 배열 인스턴스를 필요로 하지 않음.
속성
1.Length 속성: 배열의 총 길이를 반환함.
int[] numbers = { 1, 2, 3, 4, 5 };
Console.WriteLine(numbers.Length); // 출력: 5
2.GetLength 메소드: 특정 차원의 길이 반환. 다차원 배열에서 각 차원의 길이를 구할 때 유용함.
int[,] matrix = { { 1, 2 }, { 3, 4 }, { 5, 6 } };
Console.WriteLine(matrix.GetLength(0)); // 출력: 3 (행의 개수)
Console.WriteLine(matrix.GetLength(1)); // 출력: 2 (열의 개수)
3.Clear 메소드: 배열의 모든 요소를 기본값으로 초기화함.
int[] numbers = { 1, 2, 3, 4, 5 };
Array.Clear(numbers, 0, numbers.Length); // 모든 요소를 0으로 초기화
4.Copy 메소드: 하나의 배열을 다른 배열에 복사함.
int[] source = { 1, 2, 3 };
int[] destination = new int[3];
Array.Copy(source, destination, source.Length);
foreach (var item in destination)
{
Console.WriteLine(item); // 출력: 1, 2, 3
}
5.Sort 메소드: 배열의 요소를 오름차순으로 정렬함.
int[] numbers = { 3, 1, 4, 1, 5 };
Array.Sort(numbers);
foreach (var number in numbers)
{
Console.WriteLine(number); // 출력: 1, 1, 3, 4, 5
}
6.Reverse 메소드: 배열의 요소를 역순으로 정렬함.
int[] numbers = { 1, 2, 3, 4, 5 };
Array.Reverse(numbers);
foreach (var number in numbers)
{
Console.WriteLine(number); // 출력: 5, 4, 3, 2, 1
}
7.IndexOf 메소드: 특정 요소의 인덕스를 반환함. 요소가 없으면 -1을 반환함.
int[] numbers = { 1, 2, 3, 4, 5 };
int index = Array.IndexOf(numbers, 3);
Console.WriteLine(index); // 출력: 2
장점과 한계
- 다양한 배열 조작 기능: 배열의 정렬, 검색, 복사, 초기화 등 다양한 기능을 제공해 배열을 쉽게 다룰 수 있음.
- 다차원 배열 지원: 단일 배열뿐만 아니라 다차원 배열에 대해서도 다양한 조작이 가능함.
- 정적 메소드 사용의 편리함: 대부분의 메소드가 정적 메소드이므로 객체 생성 없이도 배열을 처리할 수 있음.
- 크기 변경 불가: System.Array는 제네릭 컬렉션이 아니기 때문에, 컬렉션과 달리 타입 안전성이 제한될 수 있음.
- 제너릭 미지원: System.Array는 제네릭 컬렉션이 아니기 때문에, 컬렉션과 달린 타입 안전성이 제한될 수 있음.
컬렉션(Collection): 데이터를 그룹으로 묶어 관리하고 조작을 할 수 있는 자료 구조.동적 크기 조절이 가능하여, 배열과 달린 크기를 고정하지 않고 데이터 추가 및 삭제가 가능함.
특징
- 동적 크기 조절: 컬렉션은 필요에 따라 자동으로 크기를 조정하여 데이터를 저장할 수 있음.
- 다양한 자료 구조 지원: 리스트, 큐, 스택, 딕셔너리 등 다양한 자료 구조를 제공하여, 데이터의 삽입, 삭제, 검샥, 정렬 등을 용이하게 함.
- 제네릭과 비 제네릭 지원: 제네릭 컬랙션을 사용하면 데이터 타입을 미리 지정할 수 있어, 타입 안전성과 성능을 높일 수 있음.
종류
1.제네릭 컬렉션(System.Collection.Generic): 특정 데이터 타입을 지정할 수 있는 컬렉션으로, 컴파일 시점에 타입이 고정되므로 타입 안전성을 제공하고 성능이 우수함. 형 변환이 필요없고, 컬렉션 내의 데이터 타입이 일관되게 유지됨.
- List<T>: 가변 크기의 리스트. 데이터 추가, 삭제가 가능하며 인덱스를 통해 접근 할 수 있음.
List<int> numbers = new List<int> { 1, 2, 3 };
numbers.Add(4); // 요소 추가
numbers.Remove(2); // 요소 제거
- Dictionary<TKey, TValue>: 키와 값이 쌍으로 데이터를 저장하며, 키를 통해 값에 접근할 수 있음.
Dictionary<string, int> ages = new Dictionary<string, int> { { "Alice", 30 }, { "Bob", 25 } };
Console.WriteLine(ages["Alice"]); // 출력: 30
- HashSet<T>: 중복 없는 요소를 저장하는 집합 컬랙션. 요소의 중복을 허용하지 않음.
HashSet<int> uniqueNumbers = new HashSet<int> { 1, 2, 3, 3 };
- Queue<T>:선입선출(FIFO)방식으로 요소를 처리하는 큐 자리 구조임.
Queue<string> queue = new Queue<string>();
queue.Enqueue("First");
queue.Enqueue("Second");
queue.Dequeue(); // "First"를 제거
- Stack<T>: 후입선출(LIFO)방식으로 요소를 처리하는 스택 자료 구조임.
Stack<string> stack = new Stack<string>();
stack.Push("First");
stack.Push("Second");
stack.Pop(); // "Second"를 제거
2.비제네릭 컬렉션(System.Collections): 객체 형식으로 데이터 저장. 데이터 접근 시 형 변환이 필요하며, 타입 안전성이 떨어짐.
- ArrayList: 크기가 가변적인 배열,다양한 타입의 데이터를 저장할 수 있음
ArrayList list = new ArrayList { 1, "Hello", true };
list.Add(3.14);
- Hashtable: 키-값 쌍으로 데이터를 저장하는 컬렉션으로, 제네릴 딕셔너리와 유사하지만 타입 안전성을 제공하지 않음.
Hashtable table = new Hashtable();
table["Alice"] = 30;
table["Bob"] = 25;
- Queue와 Stack: 비제네릭 컬렉션으로, Queue<T>와 Stack<T>의 제네릭 버전이 없던 시절에 주로 사용됨.
인덱서(Indexer): 클래스나 구조체가 배열처럼 인덱스를 통해 개별 요소에 접근할 수 있게 해주는 특수한 속성. 일반 속성과 비슷하지만, 매개변수를 받아 특정 위치의 데이터를 반환하거나 설정할 수 있다는 점에서 차이가 있음.
인덱스 구조: this 키워드와 대활호([])를 사용하여 정의. get과 set 접근자를 포함할 수 있음
public class SampleCollection
{
private int[] numbers = new int[10]; // 내부 배열
// 인덱서 정의
public int this[int index]
{
get { return numbers[index]; } // 인덱스를 통해 값 읽기
set { numbers[index] = value; } // 인덱스를 통해 값 설정
}
}
//사용예시
SampleCollection collection = new SampleCollection();
// 인덱스를 통해 데이터 설정
collection[0] = 10;
collection[1] = 20;
// 인덱스를 통해 데이터 읽기
Console.WriteLine(collection[0]); // 출력: 10
Console.WriteLine(collection[1]); // 출력: 20
장점
- 배열처럼 객체를 사용 가능: 객체를 배열처럼 다룰 수 있어 코드가 직관적이고 간결해짐.
- 데이터 캡슐화: 내부 데이터를 외부에서 직접 접근하지 않고 인덕스를 통해 안전하게 접근할 수 있음.
- 유연한 데이터 접근: 객체에 포함된 데이터를 특정 조건에 따라 유연하게 접근하고 수정할 수 있음.
인덱서와 속성의 차이점
- 인덱서는 매개변수를 통해 데이터를 관리할 수 있어 다수의 데이터를 다룰 때 유리함.
- 속성은 특정 필드에 대한 접근을 제어하여, 보통 단일 값을 반환하거나 설정하는데 사용됨.
- 인덱서는 이름이 없고 this 키워드를 사용하지만, 속성은 이름을 가지며 개별적으로 정의됨.
public class Student
{
private Dictionary<string, int> scores = new Dictionary<string, int>();
// 인덱서: 과목 이름을 통해 점수를 설정하고 가져온다.
public int this[string subject]
{
get { return scores.ContainsKey(subject) ? scores[subject] : 0; }
set { scores[subject] = value; }
}
// 속성: 학생의 이름을 설정하고 가져온다.
public string Name { get; set; }
}
//사용예시
Student student = new Student();
student.Name = "Alice"; // 속성을 통해 이름 설정
student["Math"] = 95; // 인덱서를 통해 점수 설정
Console.WriteLine($"Name: {student.Name}, Math Score: {student["Math"]}");
// 출력: Name: Alice, Math Score: 95
foreach 문: 컬렉션 또는 배열의 모든 요소를 순회하면서 각 요소에 접근할 수 있게 해주는 반복문. 인덱스나 조건을 사용하지 않고, 컬렉션의 처음부터 끝까지 모든 요소를 자동으로 순회하기 때문에 코드가 간결하고 가독성이 좋음. 배열, 리스트, 딕셔너리등 다양한 컬렉션과 함께 사용할 수 있으며, 내부적으로 컬렉션의 각 요소에 대해 IEnumerator 인터페이스를 사용하여 반복을 수행함.
foreach 문의 구조
foreach (var item in collection)
{
// 컬렉션의 각 요소에 대해 실행할 코드
}
- var item: 컬렉션의 각 요소가 저장될 변수. var를 사용하면 컴파일러가 자동으로 요소의 타입을 추론하며, 요소의 타입을 명시적으로 지정할 수도 있음.
- in collection: 반복할 대상 컬렉션 또는 배열.
- 반복문 블록: 컬렉션의 각 요소에 대해 실행할 코드를 정의.
int[] numbers = { 1, 2, 3, 4, 5 };
foreach (int number in numbers)
{
Console.WriteLine(number); // 각 요소를 출력
}
foreach 문의 제한 사항
- 요소 수정 불가: foreach 문에서는 컬레션의 요소를 수정할 수 없음. 수정이 필요한 경우 for문 사용.
- 모든 요소 순회: foreach 문은 걸렉션의 모든 요소를 순회하므로, 특정 조건에 따라 중간에 반복을 종료하거나 요소를 건너뛰기 어려움.
- 컬렉션 수정 제한: foreach 문을 사용하는 동안 컬렉션의 크기를 변경(요소 추가/삭제)하면 오류가 발생함.
'2024-2 > C#' 카테고리의 다른 글
10.예외 처리하기 (0) | 2024.11.10 |
---|---|
09.일반화 프로그래밍 (0) | 2024.11.10 |
07.프로퍼티 (0) | 2024.11.10 |
06.인터페이스와 추상 클래스 (1) | 2024.11.09 |
05.클래스 (2) | 2024.11.09 |