배열(Array)은 특정 타입의 요소를 고정된 개수만큼 담는 자료구조입니다. 배열의 요소들은 메모리상에 연속된 공간에 저장되므로, 인덱스만 알고 있다면 각 요소에 매우 효율적으로 접근할 수 있습니다.
배열의 선언과 초기화
C#에서 배열을 선언하고 초기화하는 기본 문법은 다음과 같습니다.
// 3개의 언어 이름을 저장할 문자열 배열 생성
string[] languages = new string[3];
배열을 선언한 후에는 대괄호([]) 표기법을 사용해 각 항목에 값을 할당할 수 있습니다.
languages[0] = "csharp";
languages[1] = "visual basic";
languages[2] = "f#";
선언과 값 할당이라는 위의 두 단계를 한 번에 처리할 수 있는 더 간결한 문법도 제공됩니다.
string[] languages = new string[] { "csharp", "visual basic", "f#" };또한 C#의 암시적 형식화 변수(var)를 활용하면 변수 이름 앞의 타입 선언을 생략할 수 있습니다.
var languages = new string[] { "csharp", "visual basic", "f#" };배열 요소 접근과 길이 확인
동일한 대괄호 표기법을 사용하면 배열의 어떤 요소든 자유롭게 읽고 쓸 수 있습니다.
string language = languages[0];
Console.WriteLine(language); // csharp 출력
배열의 Length 속성은 해당 배열에 들어 있는 항목의 개수를 반환합니다.
int count = languages.Length;
Console.WriteLine(count); // 3 출력
여기서 중요한 점 두 가지를 기억해야 합니다. 첫째, 배열은 한 번 생성되면 크기를 변경할 수 없습니다. 둘째, 배열의 범위를 벗어난 인덱스로 요소에 접근하려고 하면 예외가 발생합니다.
string lang = languages[3]; // System.IndexOutOfRangeException 발생
for와 foreach로 배열 순회하기
배열의 모든 요소를 순회하려면 C#에서 제공하는 for 루프나 foreach 루프를 사용하면 됩니다.
// for 루프
for (int i = 0; i < languages.Length; i++){
string l = languages[i];
Console.WriteLine(l); // 언어 이름을 순서대로 출력
}
// foreach 루프
foreach (string l in languages){
Console.WriteLine(l); // 언어 이름을 순서대로 출력
}
배열 요소의 기본값(Default Values)
배열을 생성하면 C# 컴파일러는 각 요소를 해당 타입의 기본값으로 자동 초기화합니다. 예를 들어 정수형(int) 배열을 생성하면 모든 요소가 0으로 설정됩니다.
var numbers = new int[3];
foreach (int num in numbers){
Console.WriteLine(num); // 0이 세 번 출력됨
}
요소가 값 타입(value type)인 경우에는 해당 타입의 각 멤버가 기본값으로 할당됩니다.
Point[] a = new Point[4];
int x = a[2].X;
Console.WriteLine(x); // 0 출력
public struct Point { public int X, Y; }
반면 참조 타입(reference type)의 경우 컴파일러는 각 항목에 대해 단순히 null 참조만 생성합니다. 따라서 객체를 생성하지 않은 상태에서 멤버에 접근하면 오류가 발생합니다.
User[] u = new User[4];
int y = u[2].Y; // NullReferenceException 발생
public class User { public int X, Y; }
이러한 오류를 방지하려면 다음과 같이 각 항목을 명시적으로 초기화해 주어야 합니다.
User[] users = new User[5];
for (int i = 0; i < users.Length; i++) // i를 0부터 끝까지 순회
users[i] = new User();
전체 예제 코드
지금까지 살펴본 내용을 하나의 프로그램으로 정리하면 다음과 같습니다.
using System;
class Program{
static void Main(){
string[] languages = new string[3]; // 문자열 배열 생성
languages[0] = "csharp";
languages[1] = "visual basic";
languages[2] = "f#";
string[] langugages_two = new string[] { "csharp", "visual basic", "f#" };
var languages_three = new string[] { "csharp", "visual basic", "f#" };
string language = languages[0];
Console.WriteLine(language); // csharp 출력
int count = languages.Length; // 3
Console.WriteLine(count);
//string lang = languages[3]; // System.IndexOutOfRangeException 발생
// for 루프
for (int i = 0; i < languages.Length; i++){
string l = languages[i];
Console.WriteLine(l); // 언어 이름을 순서대로 출력
}
// foreach 루프
foreach (string l in languages){
Console.WriteLine(l); // 언어 이름을 순서대로 출력
}
var numbers = new int[3];
foreach (int num in numbers){
Console.WriteLine(num); // 0이 세 번 출력됨
}
Point[] a = new Point[4];
int x = a[2].X;
Console.WriteLine(x); // 0 출력
User[] u = new User[4];
//int y = u[2].Y; // NullReferenceException 발생
User[] users = new User[5];
for (int i = 0; i < users.Length; i++) // i를 0부터 끝까지 순회
users[i] = new User();
}
}
public struct Point { public int X, Y; }
public class User { public int X, Y; }
실행 결과
csharp
3
csharp
visual basic
f#
csharp
visual basic
f#
0
0
0
0
정리
C# 배열은 크기가 고정되어 있지만 인덱스 기반의 빠른 접근이 가능한 기본적인 자료구조입니다. 값 타입 배열은 자동으로 기본값이 채워지는 반면, 참조 타입 배열은 null로 초기화되므로 사용 전 반드시 각 요소를 명시적으로 생성해야 한다는 점을 기억하세요. 크기가 유동적으로 변해야 하는 상황이라면 List<T> 같은 컬렉션을 사용하는 것이 더 적합합니다.