|
데이터형[] 배열명; // int[] array; |
■ 생성과 초기화
C#에서 배열은 참조형이므로 new를 통해 생성해야 하며 그렇지 않으면 참조형이 된다.
먼저 다음과 같이 선언과 동시에 생성과 초기화를 하며 숫자 배열은 초기화 때에 특별한 초기화 값이 없으면 0으로 설정되고 참조형일 때는 null이 설정된다.
구분 | 형식 |
1 | int[] nArray; nArray = new int[] {1, 2, 3 }; 또는 nArray = new int[3]{ 1, 2, 3}; |
2 | int[] nArray = new int[3] { 1, 2, 3 }; 또는 nArray = new int[] {1, 2, 3}; |
3 | int[] nArray = { 1, 2, 3 }; |
■ 사용 방법
배열의 사용방법과 형식은 C/C++과 동일하지만 Array 클래스로부터 파생된 형식이므로 배열 요소의 총 개수를 저장하고 있는
Length를 사용하면 반복문을 사용하여 쉽게 처리할 수도 있다.
다음 예는 배열을 사용하여 각 요소에 저장된 값을 출력하는 예이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | static void Main(string[] args) { int[] nArray = { 1, 2, 3, 4 }; for (int i = 0; i < 4; i++) Console.Write("{0} ", nArray[i]); Console.Write('\n');
for (int i = 0; i < nArray.Length; i++) Console.Write("{0} ", nArray[i]); Console.Write('\n');
foreach (int m in nArray) Console.Write("{0} ", m); Console.Write('\n'); string[] Days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; foreach (string str in Days) Console.Write(str + " "); } |
[소스 5-1]
[실행 결과]
1 2 3 4
1 2 3 4
1 2 3 4
Sun Mon Tue Wed Thu Fri Sat
5.2 이차원 및 다차원 배열
C#에서는 이차원 배열 이상을 선언할 때는 콤마(,)를 사용하여 배열의 면과 행, 열을 구분한다.
■ 선언
C#에서는 콤마(,)를 사용하여 다음과 같이 면과 행, 열을 나눈다.
데이터형[,] 배열명; // 이차원 배열(행, 열) 데이터형[, ,] 배열명; // 삼차원 배열(면, 행, 열) |
■ 생성과 초기화
배열은 선언만 하면 참조형이므로 실제 데이터를 저장하기 위해서는 new로 생성해야 하며 다음과 같은 형식에 따라 면과 행, 열을
생성한다.
참고적으로 다음의 형식은 면과 행, 열을 동시에 생성하거나 초기화할 때 사용하며 면과 행, 열을 개별적으로 생성할 때는 뒤에
나오는 가변 배열 형식을 사용하면 된다.
구분 | 형식 |
1 | int[,] nArray1 = new int[2, 2]; int[, ,] nArray2 = new int[2, 3, 2]; |
2 | int[,] nArray1 = new int[,]{ {1, 2}, {3, 4}}; int[, ,] nArray2 = new int[, ,]{ { {1, 2}, {3, 4}, {5, 6} }, { {7, 8}, {9, 10}, {11, 12} }; |
3 | int[,] nArray1 = new int[2,2]{ {1, 2}, {3, 4}}; int[, ,] nArray2 = new int[2,3,2]{ { {1, 2}, {3, 4}, {5, 6} }, { {7, 8}, {9, 10}, {11, 12} }; |
4 | int[,] nArray1 = { {1, 2}, {3, 4}}; int[, ,] nArray2 = { { {1, 2}, {3, 4}, {5, 6} }, { {7, 8}, {9, 10}, {11, 12} } }; |
[표 5-1]
■ 사용 방법
다차원 배열은 면, 행, 열을 C/C++과 같이 [ ] 으로 구분하지 않고 , (콤마)로 구분한다는 점이 큰 차이점이다.
이 부분이 낯선 점이지만 행과 열을 구분하기 위해 [ ]을 사용하기 보다는 ,를 사용하는 편이 오히려 간편함을 직관적으로도
알 수 있다.
그리고 행과 열에 대한 접근도 ,로 구분된 형식에서 다음 예와 같이 반복문과 함께 자유롭게 사용할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | static void Main(string[] args) { int[,] nArray1 = new int[2, 2]; nArray1[0, 0] = 1; nArray1[0, 1] = 2; nArray1[1, 0] = 3; nArray1[1, 1] = 4;
for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) Console.Write(nArray1[i, j] + " "); Console.Write('\n');
int[,] nArray2 = { { 1, 2 }, { 3, 4 } }; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) Console.Write(nArray1[i, j] + " "); Console.Write('\n');
string[,,] strArray = { { { "ab", "cd" }, { "ef", "gh" } }, { { "ij", "kl" }, { "mn", "op" } }}; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) for(int k = 0; k < 2; k++) Console.Write(strArray[i, j, k] + " "); } |
[소스 5-2]
[실행 결과]
1 2 3 4
1 2 3 4
ab cd ef gh ij kl mn op
참고적으로 foreach문을 사용하여 22행부터 25행까지를 다음과 같이 변환할 수도 있다.
22 23 | foreach(string str in strArray) Console.Write( str + “ ”); |
5.3 가변 배열
위에서 다룬 배열 형식은 항상 면, 행, 열을 선언과 동시에 결정해 주어야 하지만 가변 배열로 선언하면 필요에 따라 면, 행, 열을
유동적으로 생성하여 사용할 수 있다.
이것은 C/C++의 포인터 배열, 배열 포인터, 이중 포인터와 같은 역할을 한다.
참고적으로 C/C++에서의 유동적인 배열은 개념과 생성이 상당히 어려운 반면에 C#의 가변 배열은 보다 직관적이며 사용하기가
쉽다.
그리고 가변 배열은 일반 배열 선언과 형식에 차이가 있으므로 이를 잘 구분해야 한다.
■ 형식
데이터형[][] 배열명; // int[][] array; |
■ 생성과 초기화
가변 배열로써 열의 개수가 유동적인 이차원 배열을 생성할 때는 반드시 행을 new로 먼저 생성한 후에 임의의 개수에 따라 열을
new로 생성해야 한다.
삼차원 배열도 이차원 배열과 마찬가지로 면을 먼저 생성하고 차례대로 행과 열을 선언과 동시에 생성하면 된다.
구분 | 형식 |
1 | int[][] arrray = new int[3][]; array[0] = new int[2]; array[1] = new int[3]; array[2] = new int[4]; |
2 | int[][] array = new int[3][]; array[0] = new int[2] { 1, 2 }; array[1] = new int[3] { 3, 4, 5 }; array[2] = new int[2] { 6, 7 }; |
3 | int[][] array = new int[][]{ { new int[] {1, 2, 3}, new int[] { 4, 5}, new int[] { 6, 7, 8, 9}; } |
4 | int[][] array = { new int[] {1, 2, 3}, new int[] { 4, 5}, new int[] { 6, 7, 8, 9}; } |
[표 5-2]
■ 사용 방법
가변 배열은 다음과 같이 행과 열을 ,(콤마)가 아닌 []으로 행과 열을 구분하여 사용하므로 일반적인 배열 형식과 쉽게 구분할 수
있다.
또한 생성한 배열은 사용한 후에는 가비지 컬렉터가 알아서 해제를 해주므로 우리는 생성만 잘하면 되며 이런 부분이
‘프로그래밍적인 편의‘ 라고 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 | static void Main(string[] args) { int[][] array = new int[2][]; array[0] = new int[3] { 1, 2, 3 }; array[1] = new int[2] { 4, 5 };
for(int i = 0; i < array.Length; i++) { for (int j = 0; j < array[i].Length; j++) Console.Write(array[i][j]); } } |
[소스 5-3]
[실행 결과]
12345
다음의 예는 가변적인 다차원 배열을 생성하여 사용하는 예이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | static void Main(string[] args) { int[][][] array3 = new int[2][][]; array3[0] = new int[2][]; array3[1] = new int[3][];
array3[0][0] = new int[3] { 1, 2, 3 }; array3[0][1] = new int[2] { 4, 5 };
array3[1][0] = new int[] { 6, 7, 8 }; array3[1][1] = new int[] { 9, 10 }; array3[1][2] = new int[] { 11, 12 };
for (int i = 0; i < array3.Length; i++) { for (int j = 0; j < array3[i].Length; j++) { for(int k = 0; k < array3[i][j].Length; k++) { Console.Write("{0} ", array3[i][j][k]); } } } } |
[소스 5-4]
[실행 결과]
1 2 3 4 5 6 7 8 9 10 11 12
참고적으로 18행부터 21행까지는 다음과 같이 foreach문으로 바꿀 수도 있다.
18 19 | foreach (var k in array3[i][j]) Console.Write("{0} ", k); |
5.4 배열을 인수로 전달하기
배열은 메서드의 매개변수로 전달할 수 있으며 배열이 참조형이므로 메서드 안에서 요소의 값을 변경할 수 있다.
■ 일차원 배열을 인수로 전달
int[] array = { 1, 2, 3, 4 } 일 때 매개변수로 전달하는 형식은 다음과 같다.
void func(int[] arr) { // .... } |
위의 arr는 array를 참조하는 참조형 배열 변수이다.
그리고 다음과 같이 선언과 동시에 전달할 수도 있다.
func( new int[] {1, 2, 3, 4} ); |
다음의 예는 일차원 배열을 인수로 전달하고 메서드 안에서 값을 변경했을 때 전달하려고 했던 배열의 내용도 같이 변경되는 것을
확인하는 예이다.
이 예를 통해 배열의 참조 의미를 확인할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | static void TransArray(string[] arr) { string[] HangulDays = { "일", "월", "화", "수", "목", "금", "토" }; for(int i = 0; i < arr.Length; i++) { arr[i] = HangulDays[i]; } }
static void Main(string[] args) { string[] Days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; TransArray(Days); foreach (string str in Days) Console.Write(str); } |
[소스 5-5]
[실행 결과]
일월화수목금토
■ 다차원 배열을 인수로 전달
다차원 배열도 일차원 배열과 동일하게 참조형식으로 인수를 전달하게 되며 형식은 다음과 같다.
int[,] array2 = { {1, 2, 3}, {4, 5, 6} }; 일 때 매개변수로 전달하는 형식은 다음과 같다.
int[,] array2 = { {1, 2, 3}, {4, 5, 6} }; SetArray(array2);
void SetArray(int[,] arr) { // ..... } |
또는 매개변수 위치에서 생성과 초기화를 하는 경우는 다음과 같다.
void SetArray2(new int[,] { {1, 2, 3}, {4, 5, 6} }) { // ..... } |
5.5 배열을 리턴하는 메서드
배열을 리턴한다는 것은 참조형의 값인 배열의 최초 위치값을 리턴하는 것이므로 일차원이든 다차원이든 상관없이 배열을 리턴
받을 수 있다.
다음의 예는 일차원과 이차원 배열을 메서드에서 생성해서 리턴 받아 출력하는 예이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | static int[] CreateArray1(int nSize) { int[] Array1 = new int[nSize]; for (int i = 0; i < Array1.Length; i++) Array1[i] = i;
return Array1; }
static int[,] CreateArray2(int nRow, int nCol) { int index = 0; int[,] Array2 = new int[nRow, nCol]; for (int i = 0; i < nRow; i++) for (int j = 0; j < nCol; j++) Array2[i, j] = index++;
return Array2; }
static void Main(string[] args) { int[] nArray1; int[,] nArray2;
nArray1 = CreateArray1(5); nArray2 = CreateArray2(2, 3);
for (int i = 0; i < nArray1.Length; i++) Console.Write(nArray1[i]); Console.WriteLine(); for (int i = 0; i < 2; i++) for (int j = 0; j < 3; j++) Console.Write(nArray2[i, j]); Console.WriteLine(); } |
[소스 5-6]
[실행 결과]
01234
012345
5.6 배열의 메서드들
배열은 Array 클래스로부터 파생된 클래스이므로 Array의 메서드를 사용할 수 있다.
만약 C 언어만 학습한 학생이라면 ‘클래스’, ‘파생’, ‘메서드’ 가 조금 낯설겠지만 간단히 C언어 입장에서 생각해 보면 클래스는
구조체의 확장이며 메서드는 클래스 안에 있는 각종 함수를 의미한다. 파생은 구현은 하지 않았지만 클래스 자체가 가지고 있는
고유 기능으로 여기에는 변수와 메서드가 포함된다는 정도로만 이해하도록 하자.
뒷장이 클래스에 관한 내용이므로 이해가 어려운 경우에는 뒷장의 내용을 학습한 후에 이 부분을 다시 보기 바란다.
그리고 배열에 사용할 수 있는 메서드가 소개한 내용보다 상당히 많으므로 MSDN을 참고해야 한다.
■ 배열 초기화
배열을 사용하다보면 배열을 초기화해야 할 때가 있다.
C 언어에서는 memset()을 통해 배열의 메모리를 초기화 할 수 있었지만 C#에서는 Array.Clear()를 이용하여 쉽게 배열의 메모리를
일부분 또는 전체를 초기화 할 수 있다.
즉 배열과 관련된 메서드는 배열 자체에서 대부분 제공 받는 것이다.
네임스페이스 | System |
구문 | public static void Clear( Array array, int index, int length ) |
첫 번째 매개변수인 array에는 배열을 설정하고 index는 배열의 초기화를 시작할 인덱스, length는 초기화할 요소의 개수를
설정한다.
다음 예는 Array.Clear()를 사용하여 배열을 부분적으로 초기화하는 것과 전체를 초기화라는 예이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | static void Main(string[] args) { int[] nArray1 = { 1, 2, 3, 4, 5 }; Array.Clear(nArray1, 2, 3); foreach (int m in nArray1) Console.Write(m); Console.WriteLine();
Array.Clear(nArray1, 0, nArray1.Length); foreach (int m in nArray1) Console.Write(m); Console.WriteLine(); } |
[소스 5-7]
[실행 결과]
12000
00000
■ 배열 복사
앞에서 다룬 배열의 리턴은 배열이 참조형이므로 위치 값만을 받는 형식이어서 원본 배열에 영향을 주었다.
하지만 Clone() 메서드를 사용하면 동일한 배열을 복사해 주므로 원본에 영향을 미치지 않는다.
네임스페이스 | System |
구문 | public Object Clone() |
위의 메서드를 보면 Clone()의 리턴형이 object 이므로 리턴 받을 때는 형변환을 해야 한다.
다음의 예는 Clone() 메서드를 이용하여 배열을 복사한 후에 원본 배열에 영향을 미치는 것을 확인하는 예이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | static void Main(string[] args) { int[] nArray1 = { 1, 2, 3, 4 }; int[] nCloneArray = (int[])nArray1.Clone();
nCloneArray[2] = 30; foreach (int m in nArray1) Console.Write(m); Console.WriteLine();
foreach (int m in nCloneArray) Console.Write(m); Console.WriteLine();
string[] Days = {"일", "월", "화", "수", "목", "금", "토"}; string[] DaysClone = (string[])Days.Clone(); foreach (string str in DaysClone) Console.Write(str); } |
[소스 5-8]
[실행 결과]
1234
12304
일월화수목금토