배열 사용하기

  • 49 minutes to read

배열은 동일한 데이터 형식을 갖는 데이터들의 집합체를 의미합니다. 배열을 사용하면 편리하게 데이터들을 모아서 관리할 수 있습니다.

배열을 한 줄 정의하면 다음과 같습니다.

> // 배열(Array): 하나의 이름으로 같은 데이터 형식을 여러 개 보관해 놓는 그릇
> // 배열: 모두 동일한 데이터 형식의 연속된 개체 모음

컬렉션(Collection)

하나의 이름으로 여러 개의 데이터를 담을 수 있는 그릇을 컬렉션이라고 합니다. C#에서 다루는 컬렉션은 배열(Array), 리스트(List), 사전(Dictionary) 등이 있는데요. 먼저 배열에 대해서 학습합니다.

배열 미리보기 코드 샘플

다음 샘플 코드는 C#에서의 배열(Array)을 만들고 사용한 내용입니다. C# Interactive에서 샘플 코드들을 실행해보세요.

> var array = new string[] { "Array", "List", "Dictionary" };
> foreach (var arr in array) { Console.WriteLine(arr); }
Array
List
Dictionary

리스트 미리보기 코드 샘플

다음 샘플 코드는 C#에서의 리스트(List)를 만들고 사용한 내용입니다.

> var list = new List<string> { "Array", "List", "Dictionary" };
> foreach (var item in list) { Console.WriteLine(item); }
Array
List
Dictionary

사전 미리보기 코드 샘플

다음 샘플 코드는 C#에서의 사전(Dictionary)을 만들고 사용한 내용입니다.

> var dictionary = new Dictionary<int, string> {
.     { 0, "Array" }, { 1, "List" }, { 2, "Dictionary" } };
> foreach (var pair in dictionary) {
.     Console.WriteLine($"{pair.Key} - {pair.Value}"); }
0 - Array
1 - List
2 - Dictionary

배열(Array)

하나의 이름으로 여러 개의 데이터를 저장하는 데이터 구조를 배열(Array)이라고 합니다. 계속 반복해서 설명되는 내용인데요. 다음 내용은 가볍게 읽고 넘어갑니다.

  • 하나의 변수(Variable)에 하나의 값만을 저장할 수 있는 변수와는 달리 배열(Array)에는 하나의 배열명에 여러 개의 데이터를 보관할 수 있습니다. 이처럼 변수 여러 개를 하나의 이름으로 관리하는 것을 배열이라고합니다.
  • 배열은 요소들의 순서있는 집합입니다. 각 요소는 인덱스로 접근할 수 있습니다. 인덱스는 0부터 시작합니다.
  • 하나의 배열에는 하나의 데이터 형식(정수형 배열, 문자열 배열 등)만을 보관할 수 있습니다.
  • 배열은 메모리의 연속된 공간을 미리 할당하고 이를 대괄호([])와 0부터 시작하는 정수형 인덱스를 사용하여 접근하는 구조입니다.
  • 배열을 선언할 때에는 new 키워드를 사용하여 배열을 생성 후 사용할 수 있습니다.
  • 배열도 변수입니다.
CAUTION

n - 1(n 마이너스 1) 규칙
배열의 인덱스는 0부터 요소의 개수에서 1을 뺀 수만큼의 범위를 가집니다.

  • 5개 요소: 0 ~ 4
  • 10개 요소: 0 ~ 9

다음 그림은 변수와 배열을 그림으로 표현해 본 내용입니다.

그림: 변수(Variable)와 배열(Array)

변수(Variable)와 배열(Array)

NOTE

배열을 그림으로 표현할 때 0, 1, 2 순서로 번호를 줄 때 그림에서 아래에서 위로 그려도 되고 위에서 아래로 그려도 됩니다. 딱히 구분지을 필요는 없습니다.

요소(Element) 또는 항목(Item)

배열의 하나의 값을 요소 또는 항목으로 표현합니다.

배열 사용의 장점

배열을 사용하게되면 다음과 같은 장점이 있습니다.

  • 하나의 이름으로 여러 개의 변수를 묶어서 관리하기에 관리가 편합니다.
  • 반복문을 사용하여 쉽게 반복하여 값을 사용할 수 있습니다.
  • 정확히 필요한 데이터의 수가 정해지면 메모리를 적게 사용해 프로그램 크기가 작아집니다.
  • 읽고 쓰기 작업이 빨라 성능이 향상됩니다.

배열 사용 전

배열을 사용하지 않고 변수를 사용하여 10명의 학생의 국어 점수를 기록하는 일을 진행한다면 변수를 10개 선언해야 합니다. 하지만, 학생의 수가 20명, 30명으로 늘어날 때마다 매번 변수를 선언할 수는 없는 노릇입니다. 이런 경우에는 배열을 선언하게 되면 하나의 이름으로 20명, 30명의 학생들의 점수를 보관해서 사용할 수 있습니다.

다음 예제 코드에서는 3명의 학생의 국어 점수 총합을 계산합니다. 이 방식을 활용하면, 학생 수가 30명으로 늘어날 경우 30개의 변수가 필요하게 됩니다. 이처럼 많은 변수를 관리하기 위해서는 배열의 사용이 필수적입니다

코드: WhyArray.cs

//[?] 배열을 사용하지 않고 3명의 학생의 국어 점수의 총점을 구하려면? 
> var kor1 = 90; // 1번 학생
> var kor2 = 80; // 2번 학생
> var kor3 = 70; // 3번 학생
> var tot = kor1 + kor2 + kor3;
> $"총점: {tot}"
"총점: 240"

문자열에서 문자 하나씩 뽑아오기

배열을 사용하기 전에 문자들의 집합인 문자열을 분해해 보겠습니다. 우리가 흔히 말하는 문자열은 문자의 배열을 말합니다. 문자열은 그 자체를 문자 배열로 분리해서 사용할 수 있습니다. 문자열을 분해해서 문자 하나씩 출력하는 내용을 살펴보겠습니다.

코드: ArrayString.cs

> // 문자열 == 문자의 배열
> string arr = "C#11";
> Console.WriteLine(arr[0]); // C
C
> Console.WriteLine(arr[1]); // #
#
> Console.WriteLine(arr[2]); // 1
1
> Console.WriteLine(arr[3]); // 1
1

문자열 변수 뒤에 [0], [1], [2], [3] 코드를 붙여서 0번째 위치부터 n - 1번째 위치까지에 들어있는 문자 하나씩을 빼내올 수 있습니다. 이처럼 0번째부터 시작하는 숫자를 인덱스(Index) 또는 첨자(Subscript)라 부릅니다.

문자열에 직접 인덱서([]) 사용하기

변수명이 아닌 문자열 자체에 직접 인덱서([]) 기호를 사용하여 특정 인덱스에 해당하는 문자 값을 뽑아낼 수 있습니다. 문자열에서 직접 문자 하나를 뽑아내는 내용을 살펴보겠습니다.

코드: StringIndexer.cs

> //[?] 문자열 인덱서: 문자열에 직접 인덱서([]) 사용하기 
> "ABC"[0]
'A'
> "ABC"[1]
'B'
> "ABC"[2]
'C'
> "ABC".GetType()
[System.String]
> "ABC"[0].GetType()
[System.Char]
> 

위와 같이 문자열에서 인덱서 기호인 []를 사용하여 뽑아낸 자료 하나는 문자 데이터인 Char 형식이 됩니다.

배열 선언하기

배열의 선언은 데이터 형식 이름 뒤에 [] 기호를 사용하여 배열을 선언합니다. 배열에 저장된 데이터는 정수형 인덱스(Index)를 통해서 접근 가능합니다. 배열에 있는 데이터를 출력할 때에는 for 문 또는 foreach문 등을 사용하여 쉽게 반복하여 출력합니다.

그림: 배열 표기법

배열 표기법

예를 들어, 정수형 배열은 다음과 같이 선언할 수 있습니다.

> int[] numbers;

배열의 요소 수 생성하는 방법에 대해서 살펴보겠습니다. 배열 선언 후 new 키워드를 사용하여 배열의 크기만큼 메모리 영역을 잡을 수 있습니다. 배열 선언시 사용된 new 키워드는 형식을 인스턴스화(Instantiate)시켜주는 연산자입니다. new 키워드는 특정 형식(여기서는 배열)을 실제 사용 가능한 개체로 만들어 줍니다. 말이 조금 어렵죠? 쉽게 말해서 new 키워드는 배열을 지정한 크기로 만들어주는 연산자라고 쉽게 이해해도 됩니다. 참고로, 프로그래밍에서 인스턴스(Instance)라는 단어는 새로운 실체 또는 개체(Object)를 말합니다. 즉, 새로운 개체를 만드는 작업을 인스턴스화라고 합니다.

정수형 배열을 선언한 후 요소 수를 생성은 다음과 같이 할 수 있습니다. 한 줄로 줄여서 표현해도 됩니다.

> int[] numbers;
> numbers = new int[3];

배열의 크기 생성시 사용되는 숫자를 첨자(Subscript)라고 부릅니다. 첨자는 흔히 인덱스라고 합니다.

> int[] intArray = new int[3];

위와 같은 코드에서 intArray의 첨자는 3입니다.

선언된 배열은 0부터 시작하는 인덱스(Index)를 사용하여 접근할 수 있습니다.

intArray[0], intArray[1], intArray[2] 순서대로 첨자 3으로 선언된 배열은 0, 1, 2의 3개의 인덱스를 가집니다. 우리가 일상 생활에서는 1부터 숫자를 세지만 C#에서는 0부터 숫자를 세는 구조입니다. 이러한 규칙을 0 기반(Zero Base) 또는 (n – 1) 규칙이라고도 합니다. 인덱스는 0부터 n - 1(전체 요소에서 한개를 뺀)까지 배열과 컬렉션의 요소를 반복해서 출력해 주는 용도로 사용됩니다.

배열을 만드는 방법을 한글로 표현하면 다음과 같습니다.

데이터 형식[] 배열 이름 = new 데이터 형식[크기];

이러한 배열에는 다음과 같은 종류가 있습니다.

  • 1차원 배열: 배열의 첨자를 하나만 사용하는 배열
  • 다차원 배열: 2개 이상의 첨자를 사용하는 배열(2차원, 3차원, …)
  • 가변(Jagged) 배열: "배열의 배열"이라고도 하며 하나의 이름으로 다양한 차원의 배열을 표현

1차원 배열 선언, 초기화 참조

1차원 배열을 선언하여 메모리 영역의 확보하는 코드는 다음 형태를 가집니다.

데이터형식[] 배열명;

1차원 배열의 요소에 값을 대입하는 코드는 다음과 같습니다.

 배열명[인덱스] = 값;

1차원 배열의 참조는 정수형 인덱스를 사용하여 접근할 수 있습니다.

Console.WriteLine(배열명[인덱스]);

1차원 배열 관련 용어에서 인덱스와 첨자는 같은 뜻으로 사용되며, 인덱스를 사용하여 하나의 배열 요소를 가져올 수 있습니다.

  • 인덱스 또는 첨자
    • 복수의 데이터를 구분 짓는 번호
    • int[] intNum = new int[10]; <- 여기서 숫자 10이 인덱스(첨자)
  • 요소
    • 배열의 요소: 하나의 첨자를 가지는 배열
    • 사원번호[3] <- 3번 인덱스에 위치한 배열의 요소

1차원 배열 사용 예제

다음과 같이 arr 이름의 배열을 선언하면, 메모리 상에 다음과 같이 5개의 공간이 잡힙니다.

> int[] arr = new int[5];

1차원 배열의 인덱스

인덱스가 5이므로 C#에서의 배열의 첨자는 0부터 시작해서 선언할 때의 첨자인 (5 - 1)까지의 5개가 만들어집니다. C#에서는 n - 1 규칙 또는 0 베이스(Zero Base) 또는 제로 오프셋(Zero Offset)이라고 해서 모든 배열과 같은 데이터 구조의 인덱스는 0번째부터 사용됨을 기억하기 바랍니다.

1차원 배열 만들기

자, 처음으로 1차원 배열을 만들어 보도록 하겠습니다. 하나의 이름인 numbers로 2개의 정수를 저장하는 예제입니다. ushort 형식을 한 번 사용해보는 예제이기에 ushort 대신에 int를 사용해도 됩니다.

코드: ArrayDescription.cs

> //[?] 1차원 배열 만들기
> //[1] 배열 선언
> ushort[] numbers;
> 
> //[2] 배열의 요소수 생성
> numbers = new ushort[2]; // 요소수가 2이므로, [0], [1] 사용 
> 
> //[3] 배열 초기화
> numbers[0] = 3840;
> numbers[1] = 2160;
> 
> //[4] 배열 사용
> Console.WriteLine($"{numbers[0]} * {numbers[1]}"); // 3840 * 2160
3840 * 2160

정수형 배열인 numbers를 생성한 후 2개의 요소수를 new 키워드를 통해서 할당합니다. 배열의 요소수를 직접 지정할 때에는 반드시 new 키워드를 사용합니다.

요소수를 2로 선언했으므로 [0], [1]의 2개의 요소가 생성됩니다. 각각의 요소에는 [0], [1] 형태의 인덱스를 통해서 값을 할당할 수 있습니다.

배열의 값은 numbers[n] 형태로 가져와 사용할 수 있습니다. 만약, 2개의 요소를 지정하여 배열을 만들면 0, 1의 인덱스를 사용할 수 있지만, 다음과 같이 2를 지정하면 에러가 발생합니다.

> ushort[] numbers = new ushort[2];
> numbers[2]
인덱스가 배열 범위를 벗어났습니다.

1차원 배열에 문자열 저장하기

이번에는 문자열 정보를 여러 개 저장하는 1차원 배열을 사용해 보겠습니다.

코드: ArrayDemo.cs

> //[?] 1차원 배열에 문자열 저장하기
> //[1] 배열 생성
> string[] phones;
> 
> //[2] 배열 요소 생성
> phones = new string[2];
> 
> //[3] 배열에 값 대입
> phones[0] = "112";
> phones[1] = "119";
> 
> //[4] 배열 값 사용
> Console.WriteLine("{0}, {1}", phones[0], phones[1]); // 112, 119
112, 119

문자열 배열을 선언하고 2개로 요소를 생성합니다. 각각의 요소에는 "112""119"의 값을 넣어놓고 출력해 본 내용입니다.

배열 선언과 동시에 초기화해서 코드 줄이기

지금부터는 4단계에 걸쳐 배열을 선언하고 초기화해서 코드를 줄여 나가는 내용을 보여드리겠습니다. 우선, 다음 코드와 같이 선언 따로 요소 수 생성 따로 초기화 따로 하는 코드를 살펴보겠습니다.

코드: ArrayOne1.cs

//[?] 1차원 배열을 선언/초기화하는 프로그램
using System;

class ArrayOne1
{
    static void Main()
    {
        int[] intArray; // 일차원 배열 선언
        intArray = new int[3]; // 메모리 영역 확보(0, 1, 2)

        intArray[0] = 1; // 배열 초기화
        intArray[1] = 2;
        intArray[2] = 3;

        //[1] for문 사용 출력: 정확하게 배열의 범위를 알고 있을 때
        for (int i = 0; i < 3; i++) // 배열 참조
        {
            Console.WriteLine($"{i}번째 인덱스: {intArray[i]}");
        }

        //[2] foreach문 사용 출력: intArray에 데이터가 있는 동안 반복
        foreach (int intValue in intArray)
        {
            Console.WriteLine("{0}", intValue);
        }
    }
}
0번째 인덱스: 1
1번째 인덱스: 2
2번째 인덱스: 3
1
2
3

이번에는 위 코드를 한 단계 더 줄여서 선언과 동시에 초기화하는 코드로 변환해 보겠습니다.

코드: ArrayOne2.cs

using System;

class ArrayOne2
{
    static void Main()
    {
        //[!] 1차원 배열 선언, 요소 생성, 초기화를 동시에...
        int[] intArray = new int[3] { 1, 2, 3 };

        //[1] for문 사용 출력: 정확하게 배열의 범위를 알고 있을 때
        for (int i = 0; i < 3; i++) // 배열 참조
        {
            Console.WriteLine($"{i}번째 인덱스: {intArray[i]}");
        }

        //[2] foreach문 사용 출력: intArray에 데이터가 있는 동안 반복
        foreach (int intValue in intArray)
        {
            Console.WriteLine("{0}", intValue);
        }
    }
}
0번째 인덱스: 1
1번째 인덱스: 2
2번째 인덱스: 3
1
2
3

배열 선언 시 바로 요소 생성 및 초기화할 수 있습니다. 이런 경우에는 var 키워드로 코드를 줄일 수 있습니다. 또한, 요소 수를 생략할 수 있습니다.

코드: ArrayOne3.cs

using System;

class ArrayOne3
{
    static void Main()
    {
        // 1차원 배열 선언, 요소 생성, 초기화를 동시에...
        // 요소 수 생략 가능: 생략하면 뒤에서 지정한 요소의 수만큼 자동 생성
        var intArray = new int[] { 1, 2, 3 };

        //[1] for문 사용 출력: 정확하게 배열의 범위를 알고 있을 때
        for (int i = 0; i < 3; i++) // 배열 참조
        {
            Console.WriteLine($"{i}번째 인덱스: {intArray[i]}");
        }

        //[2] foreach문 사용 출력: intArray에 데이터가 있는 동안 반복
        foreach (int intValue in intArray)
        {
            Console.WriteLine("{0}", intValue);
        }
    }
}
0번째 인덱스: 1
1번째 인덱스: 2
2번째 인덱스: 3
1
2
3

마지막으로 선언과 동시에 초기화할 때에는 new 키워드와 배열형([])까지 생략할 수 있습니다.

코드: ArrayOne4.cs

using System;

class ArrayOne4
{
    static void Main()
    {
        // 1차원 배열 선언, 요소 생성, 초기화를 동시에...
        // new 키워드와 int[] 생략하고 바로 초기화 가능
        int[] intArray = { 1, 2, 3 };

        //[1] for문 사용 출력: 정확하게 배열의 범위를 알고 있을 때
        for (int i = 0; i < 3; i++) // 배열 참조
        {
            Console.WriteLine($"{i}번째 인덱스: {intArray[i]}");
        }

        //[2] foreach문 사용 출력: intArray에 데이터가 있는 동안 반복
        foreach (int intValue in intArray)
        {
            Console.WriteLine("{0}", intValue);
        }
    }
}
0번째 인덱스: 1
1번째 인덱스: 2
2번째 인덱스: 3
1
2
3

4단계를 거쳐서 1차원 배열을 선언하고, 요소 수를 생성하고, 요소의 값을 초기화하고 이를 출력하는 내용을 살펴보았습니다.

문자열 배열 선언과 동시에 초기화하여 출력하기

다음 코드는 문자열 배열을 생성한 후 3개의 문자열을 입력 후 배열의 인덱스를 사용하여 출력하는 내용입니다. 코드를 입력한 후 실행해 보세요.

코드: ArrayLanguages.cs

> string[] languages = { "Korean", "English", "Spanish" };
> Console.WriteLine($"{languages[0]}, {languages[1]}, {languages[2]}");
Korean, English, Spanish

문자열 배열을 선언과 동시에 new 키워드없이 바로 중괄호를 사용하여 요소 수를 생성과 동시에 초기화할 수 있습니다. 마찬가지로 배열에 들어있는 값은 [0], [1], [2] 식으로 정수형 인덱스를 사용하여 출력할 수 있습니다.

위 코드의 주석 처리한 부분보다는 숫자 구분자를 사용한 부분이 숫자 요소의 내용을 확인할 때 좀 더 가독성이 좋아집니다.

이진수 리터럴(Binary Literal)을 배열에 저장하기

1차원 배열에 이진수 리터럴을 저장 후 출력해보겠습니다.

코드: BinaryLiteralDemo.cs

> // Binary Literal
> //int[] numbers = {1, 2, 4, 8};
> int[] numbers = { 0b1, 0B10, 0b0100, 0B00001000 }; // 이진수가 저장된 배열
> 
> foreach (var n in numbers)
. {
.     Console.WriteLine(n);
. }
1
2
4
8

이진수 리터럴을 사용하여 4개의 이진수 데이터를 1차원 정수 배열에 저장 후 출력해 보는 간단한 예제였습니다.

이진수 리터럴과 숫자 구분자를 사용하면 여러 데이터에 대한 가독성이 좋아집니다.

코드: BinaryLiteralNote.cs

> // 0b 접두사를 붙이고 이진수를 4자리 단위로 표시 가능
> int[] numbers = { 0b1, 0b10, 0b100, 0b1000, 0b1_0000, 0b10_0000 };
> numbers[0]
1
> numbers[1]
2

다음 샘플 코드처럼 이진수 리터럴과 숫자 구분자를 함께 쓰면 더욱 더 가독성이 좋아지겠죠?

코드: DigitSeparatorDescription.cs

> int[] numbers = { 0b1, 0B10, 0b0100, 0B0000_1000 };
> numbers
int[4] { 1, 2, 4, 8 }

Length 속성으로 배열의 크기 구하기

배열의 크기인 요소 수를 얻으려면 [배열이름.Length] 형태로 Length 속성(Property)을 사용합니다. 배열은 0부터 시작하는 정수형 인덱스를 사용하기에 주로 for 문과 같은 반복문과 함께 사용됩니다.

문자 여러 개를 배열에 저장 후 출력하는 예제를 살펴보겠습니다.

코드: CharacterArray.cs

> char[] characters = { 'a', 'b', 'c', 'd' }; // 문자 배열
> characters.Length
4
> 
> for (int i = 0; i < characters.Length; i++) // 배열의 크기만큼 반복
. {
.     Console.WriteLine(characters[i]);
. }
a
b
c
d

배열의 내용을 출력할 때에는 for 문과 같은 반복문을 사용하면 편리하게 많은 수의 배열 요소를 출력할 수 있습니다. 배열 형식의 Length 속성을 사용하면 반복문에서의 반복 범위를 쉽게 결정할 수 있습니다.

배열 인덱스에 증감 연산자 사용하기

배열의 인덱스는 정수형이기에 다음 코드와 같이 증감 연산자와 함께 사용도 가능합니다. 여기서 주의할 점은 인덱스가 정해진 크기를 벗어나면 에러가 발생됩니다.

코드: ArrayIndex.c

> // array 이름으로 1차원 배열 선언과 동시에 1, 2, 3으로 값 초기화
> int[] array = { 1, 2, 3 };
> array[3]
System.IndexOutOfRangeException: 인덱스가 배열 범위를 벗어났습니다.
> 
> int index = 0; // 배열의 인덱스는 0부터 시작하기에 0으로 index 변수 초기화
> 
> Console.WriteLine(array[index++]); // array[0] 출력 후, index == 1로 증가 
1
> Console.WriteLine(array[index++]); // array[1] 출력 후, index == 2로 증가 
2
> Console.WriteLine(array[index++]); // array[2] 출력 후, index == 3로 증가 
3
> 
> Console.WriteLine(array[--index]); // index == 2로 감소 후, array[2] 출력 
3
> Console.WriteLine(array[--index]); // index == 1로 감소 후, array[1] 출력 
2
> Console.WriteLine(array[--index]); // index == 0로 감소 후, array[0] 출력 
1
> 
> array[--index]
System.IndexOutOfRangeException: 인덱스가 배열 범위를 벗어났습니다.

배열의 인덱스를 지정하는 [] 영역에는 정수형 값이 필요합니다. 이 정수형 값을 표현할 때에는 ++, --와 같은 증감 연산자를 함께 사용할 수 있습니다.

배열을 사용하여 국어 점수의 총점과 평균 구하기

이번에는 배열을 사용하여 국어 점수의 총점과 평균을 구하는 프로그램을 만들어보겠습니다. 만약, 배열을 사용하지 않는다면 3명의 학생의 점수를 저장하는 변수를 3개 선언해야 합니다. 50명의 학생이라면 50개의 변수를 선언해야합니다. 배열을 사용하면 여러 개의 데이터를 처리할 때 편리하게 사용할 수 있습니다.

코드: ArrayTotalAvg.cs

using System;

class ArrayTotalAvg
{
    static void Main()
    {
        int[] kor = new int[3]; // 3개의 int 형식 요소를 갖는 1차원배열 선언
        int sum = 0; // 합계가 담길 변수 sum 선언과 동시에 0으로 초기화
        float avg = 0; // 평균이 담길 실수형 변수 avg 선언과 동시에 0으로 초기화

        kor[0] = 100; // 배열의 각 요소에 값 대입
        kor[1] = 90;
        kor[2] = 80;

        sum = kor[0] + kor[1] + kor[2];     // 총점 계산
        avg = sum / (float)3.0;             // 평균 계산

        // 총점과 평균 출력: 평균은 소수점 2자리까지 출력
        Console.WriteLine($"총점: {sum}, 평균: {avg:0.00}");
    }
}
총점: 270, 평균: 90.00

총점을 구하는 부분을 수작업으로 진행했지만, 반복문을 사용해서 합계를 구하면 훨씬 편합니다. 참고로, 실수형 자료에 대해선 다음과 같이 간단히 소수 둘째자리까지 표현이 가능합니다.

> $"{3.141592:0.00}"
"3.14"

국어점수_총점_평균_차이_일차원 배열을 사용한 간단한 성적 관리 예제 만들기

코드: 국어점수_총점_평균_차이.cs

// 5명의 학생의 국어 점수를 배열에 저장 후 총점과 평균을 구하고 
// 각 학생의 평균과의 차이를 구하는 프로그램을 작성합니다.
// 입력 값: 100, 90, 80, 70, 60
using System;

class 국어점수_총점_평균_차이
{
    static void Main()
    {
        int[] kor = { 100, 90, 80, 70, 60 };
        int tot = 0;        // 총점
        float avg = 0.0f;   // 평균
        
        for (int i = 0; i < kor.Length; i++)
        {
            tot = tot + kor[i];
        }
        avg = tot / (float)kor.Length;

        Console.WriteLine("총점: {0,3}, 평균: {1,3}\n", tot, avg);
        for (int i = 0; i < kor.Length; i++)
        {
            float diff = kor[i] - avg; // 차이
            Console.WriteLine("점수: {0,3}, 차이: {1,3}", kor[i], diff);
        }
    }
}
총점: 400, 평균:  80

점수: 100, 차이:  20
점수:  90, 차이:  10
점수:  80, 차이:   0
점수:  70, 차이: -10
점수:  60, 차이: -20

값 입력 받아 배열에 저장한 후 출력하기

이번에는 Console.ReadLine() 메서드로 입력된 값을 배열에 저장한 후 출력해보도록 하겠습니다.

콘솔에서 반드시 3개의 정수를 입력해야 정상 실행됩니다.

코드: ArrayStudents.cs

// 3명의 학생의 점수를 입력받아 총점을 구하는 프로그램
using System;

class ArrayStudents
{
    static void Main()
    {
        // 3개의 요소를 가지는 1차원 배열 생성
        int[] students = new int[3];

        // 사용자로부터 정수 데이터 3개 입력받아 배열에 저장
        students[0] = Convert.ToInt32(Console.ReadLine());
        students[1] = Convert.ToInt32(Console.ReadLine());
        students[2] = Convert.ToInt32(Console.ReadLine());

        // 총점 구하고 출력하기 
        int total = students[0] + students[1] + students[2];
        Console.WriteLine($"총점: {total}");
    }
}
100
90
80
총점: 270

콘솔로부터 입력된 정수를 3개의 배열 요소로 받은 후 3개의 값을 더하여 출력하는 간단한 예제입니다.

배열의 값을 foreach 문으로 반복해서 출력하기

앞서 몇 번 나왔던 내용인데요. 이번에는 foreach문을 사용하여 배열의 값을 반복해서 출력하는 방법을 알아보겠습니다.

코드: ArrayForEach.cs

> //[?] foreach문으로 배열의 값을 반복해서 사용
> // float 형식의 데이터를 3개 저장하는 1차원 배열 arr 생성
> float[] arr = { 10.5f, 20.1f, 30.2f };
> 
> float sum = 0.0f; // 배열의 합을 저장해 놓을 sum 변수 선언과 동시에 0으로 초기화
> 
> foreach (float f in arr) // arr 변수에 데이터가 있는 동안 반복해서 실행
. {
.     sum += f; // 각각의 요소를 sum 변수에 누적
. }
> 
> sum
60.8000031
> 
> Console.WriteLine(sum); // 60.8
60.8

실수형 배열인 arr 생성 후 3개의 값으로 초기화 합니다. 배열의 데이터는 foreach 문을 사용하여 있는 만큼 반복하여 가져와 사용할 수 있습니다.

참고로, 중간에 sum을 출력해보니 60.8000031과 같이 오차가 발생합니다. 이러한 경우에는 좀 더 정밀한 데이터로 바꿔 사용할 수 있습니다. 다음 코드처럼 float 형식을 decimal 형식으로 변경하면 됩니다.

코드: ArrayForEach.cs

> decimal[] arr = { 10.5M, 20.1M, 30.2M };
> decimal sum = 0.0M;
> foreach (decimal d in arr)
. {
.     sum += d;
. }
> sum
60.8
> Console.WriteLine(sum);
60.8

참고: 빈 배열

C#에서는 배열 선언시 {} 를 사용하여 빈 배열을 만들 수는 있습니다. 하지만, 배열은 선언 후 크기를 동적으로 다시 설정할 수 없기 때문에 빈 배열은 만들어도 쓸모가 없어집니다.

빈 배열의 크기는 항상 0입니다. 다음 코드를 살펴보세요.

코드: ArrayEmpty.cs

using System;

class ArrayEmpty
{
    static void Main(string[] args)
    {
        // 빈 배열 선언
        string[] authors = { };
        if (authors.Length > 0)
        {
            Console.WriteLine($"글쓴이가 {authors.Length}명 있습니다.");
        }
        else
        {
            Console.WriteLine($"글쓴이가 아무도 없습니다.");
        }
    }
}
글쓴이가 아무도 없습니다.

다차원 배열

2차원 배열 및 3차원 배열과 같이 차원이 2 이상인 배열을 다차원 배열이라고 합니다.

다차원 배열은 다음과 같이 선언합니다.

데이터형식[,] 배열이름; // 2차원 배열을 선언합니다. 
데이터형식[,,] 배열이름; // 3차원 배열을 선언합니다.

2행 3열 배열을 선언하면 다음 그림과 같습니다.

그림: 2차원 배열의 인덱스

2차원 배열의 인덱스

1차원, 2차원, 3차원 배열을 선언하는 방법은 다음과 같습니다. C#에서 배열을 선언할 때에는 콤마를 기준으로 차원을 구분합니다.

// 배열 선언
int[] oneArray;         // 1차원 배열 선언
int[,] twoArray;        // 2차원 배열 선언
int[,,] threeArray;     // 3차원 배열 선언

배열이 선언되고 나서 배열을 사용하려면 값을 초기화할 수 있는데, 차수별 배열을 초기화하는 모양은 다음과 같습니다.

// 배열 초기화: 배열이름 = new 데이터형식[요소수, 요소수];
oneArray = new int[2] { 1, 2 };
twoArray = new int[2, 2] { { 1, 2 }, { 3, 4 } };
threeArray = new int[2, 2, 2] { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } };

삼차원 배열 만들기

3차원 배열을 만들어 보겠습니다.

코드: ArrayThreeDescription.cs

//[?] 3차원 배열(층, 행, 열)
using System;

class ArrayThreeDescription
{
    static void Main()
    {
        //[1] 3차원 배열 선언
        string[,,] names = new string[2, 2, 2]; // 2*2*2=8

        //[2] 3차원 배열 초기화
        names[0, 0, 0] = "C#";
        names[0, 0, 1] = "ASP.NET";

        names[0, 1, 0] = "Windows Forms";
        names[0, 1, 1] = "WPF";

        names[1, 0, 0] = "Xamarin";
        names[1, 0, 1] = "Unity";

        names[1, 1, 0] = "UWP";
        names[1, 1, 1] = "Azure";

        //[3] 3차원 배열 사용
        Console.WriteLine("\n0층");
        Console.WriteLine($"{names[0, 0, 0],20}, {names[0, 0, 1],20}");
        Console.WriteLine($"{names[0, 1, 0],20}, {names[0, 1, 1],20}");

        Console.WriteLine("\n1층");
        Console.WriteLine($"{names[1, 0, 0],20}, {names[1, 0, 1],20}");
        Console.WriteLine($"{names[1, 1, 0],20}, {names[1, 1, 1],20}");
    }
}

0층
                  C#,              ASP.NET
       Windows Forms,                  WPF

1층
             Xamarin,                Unity
                 UWP,                Azure

3차원 배열은 행과 열로 이루어진 2차원 배열을 층으로 쌓아서 관리하는 형태의 데이터 구조를 다룰 때 사용됩니다. 3개의 인덱스를 사용하기에 꽤 복잡하지만, 평상시에는 많이 사용되지 않는 데이터 구조이기에 예제로만 살펴보면 됩니다.

3차원 배열 만들고 3개의 for 문으로 출력하기

이번에는 삼차원 배열을 반복문으로 출력해 보겠습니다.

코드: ArrayThree.cs

using System;

class ArrayThree
{
    static void Main()
    {
        int[,,] intArray = new int[2, 3, 4] 
        { 
            // 0층
            { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }, 
            // 1층
            { { 13, 14, 15, 16 }, { 17, 18, 19, 20 }, { 21, 22, 23, 24 } }
        };

        for (int i = 0; i < 2; i++) // 층 반복
        {
            for (int j = 0; j < 3; j++) // 행 반복
            {
                for (int k = 0; k < 4; k++) // 열 반복
                {
                    Console.Write("{0,2} ", intArray[i, j, k]);
                }
                Console.Write("\n");
            }
            Console.WriteLine();
        }
    }
}
1  2  3  4
5  6  7  8
9 10 11 12

13 14 15 16
17 18 19 20
21 22 23 24


[,,] 형태로 3차원 배열을 선언하고 의미상으로 , , 로 이루어진 데이터 구조를 저장할 수 있습니다. 3차원 배열은 3개의 for 문을 사용하여 각 차원을 구분해서 출력합니다. 3차원 배열은 개발 학습 환경에서는 사용 빈도가 적으니 위 예제 정도만 실행해보는 정도로 넘어갑니다.

모든 배열은 배열의 요소 수 및 각 차원에 해당 요소의 크기를 확인할 수 있습니다.

배열은 Length 속성을 사용하여 배열의 길이를 알 수 있습니다. 추가적으로 Rank 속성을 사용하면 배열의 차수를 구할 수 있는데 3차원 배열이면 3을 반환합니다. 또한 각 차수에 해당하는 길이를 알고자할 때에는 GetLength(n)을 사용하여 GetLength(0), GetLength(1), GetLength(2) 형태로 1차원, 2차원, 3차원의 Length를 구할 수 있습니다.

배열 관련 Rank, Length 속성과 GetLength() 메서드 사용하기

3차원 배열 선언하고 RankLength 그리고 GetLength()를 사용해보겠습니다.

코드: ArrayGetLengthDemo.cs

using System;

class ArrayGetLengthDemo
{
    static void Main()
    {
        // 3차원 배열 선언/요소수생성/초기화: 층/행/열
        int[,,] arr = new int[2, 2, 2] 
            { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } };
        // 차수 출력
        Console.WriteLine("차수 출력: {0}", arr.Rank);
        // 길이 출력
        Console.WriteLine("길이 출력: {0}", arr.Length);
        // 층(면), 행, 열 구분해서 출력
        for (int i = 0; i < arr.GetLength(0); i++) // 층
        {
            for (int j = 0; j < arr.GetLength(1); j++) // 행
            {
                for (int k = 0; k < arr.GetLength(2); k++) // 열
                {
                    Console.Write("{0}\t", arr[i, j, k]);
                }
                Console.WriteLine(); // 줄바꿈
            }
            Console.WriteLine(); // 줄바꿈
        }
    }
}
차수 출력: 3
길이 출력: 8
1       2
3       4

5       6
7       8


배열의 Rank 속성으로 1차원, 2차원, 3차원 배열을 구분할 수 있습니다. 또한, 각각의 차원의 LengthGetLength() 메서드를 통해서 구할 수 있습니다.

만약, numbers 배열이 2행 3열짜리 2차원 배열이라면, GetLength(0)을 사용하여 행의 길이인 2를, 그리고 GetLength(1)을 사용하여 열의 길이인 3을 구할 수 있습니다.

가변 배열

차원이 2개 이상인 배열이 다차원 배열이고 배열의 길이가 가변 길이인 배열을 가변 배열(Jagged)이라고 합니다.

1년 12개월의 데이터를 보관하는 그릇을 구성한다면 1월달은 31일, 2월달은 28일 또는 29일, 3월달은 31일 형태로 지그재그 형태의 데이터를 보관할 때 가변 배열이 사용될 수 있습니다.

가변 배열의 사용 예제를 살펴보겠습니다.

코드: ZigZag.cs

// 지그재그 배열
// 데이터형식[][] 배열이름;
// int[][] zagArray; 
using System;

class ZigZag
{
    static void Main()
    {
        // 배열 요소수 생성시 [2][] 형태로 2번째를 비워두면 동적으로 n개의 자료로 초기화 가능
        int[][] zagArray = new int[2][];

        zagArray[0] = new int[] { 1, 2 }; // 0번째 행에 2개의 요소로 초기화
        zagArray[1] = new int[] { 3, 4, 5 }; // 1번째 행에 3개의 요소로 초기화 

        for (int i = 0; i < 2; i++)
        {
            // n번째 행의 길이만큼 반복: 2번, 3번 반복
            for (int j = 0; j < zagArray[i].Length; j++)
            {
                Console.Write($"{zagArray[i][j]}\t");
            }
            Console.WriteLine();
        }
        Console.WriteLine();
    }
}
1       2
3       4       5


가변 배열을 사용하여 [0]번째 행에는 2개의 데이터를 저장하고 [1]번째 행에는 3개의 데이터를 저장 후 데이터가 있는 만큼 출력해 보았습니다.

// JaggedArray.cs
using System;

public class JaggedArray
{
    static void Main()
    {
        // Jagged array 생성, 3개의 다른 크기의 배열을 가진다.
        int[][] jaggedArray = new int[3][];

        jaggedArray[0] = new int[5] { 1, 2, 3, 4, 5 }; // 첫 번째 배열은 5개의 요소를 가짐
        jaggedArray[1] = new int[3] { 6, 7, 8 };       // 두 번째 배열은 3개의 요소를 가짐
        jaggedArray[2] = new int[4] { 9, 10, 11, 12 }; // 세 번째 배열은 4개의 요소를 가짐

        // Jagged array의 모든 요소를 출력
        for (int i = 0; i < jaggedArray.Length; i++)
        {
            for (int j = 0; j < jaggedArray[i].Length; j++)
            {
                Console.Write(jaggedArray[i][j] + " ");
            }
            Console.WriteLine();
        }
    }
}
1 2 3 4 5
6 7 8
9 10 11 12

위 소스는 Jagged Array를 생성하고, 각 요소에 값을 할당한 후, 이 값들을 모두 출력합니다. Jagged Array는 배열의 배열로, 각 서브 배열은 다른 길이를 가질 수 있습니다. 이 예제에서는 첫 번째 서브 배열에 5개, 두 번째 서브 배열에 3개, 세 번째 서브 배열에 4개의 요소를 할당합니다.

var 키워드로 배열 선언하기

이미 우리는 var 키워드를 사용하여 변수를 선언하는 방법을 알고 있습니다. 마찬가지로 배열도 선언과 동시에 초기화할 때 배열 이름 앞에 int[]와 같은 배열 형식 대신에 var 키워드를 사용하여 배열을 선언할 수 있습니다.

변수 선언 시 var 키워드를 사용한 후 입력한 값의 형식을 GetType() 메서드로 출력해보겠습니다.

코드: ArrayWithVarKeyword.cs

using System;

class ArrayWithVarKeyword
{
    static void Main()
    {
        // 정수 형식으로 자동적으로 형식이 설정됨
        var i = 5; // int i = 5; 
        Console.WriteLine("i : {0}, 타입 : {1}", i, i.GetType());

        // 문자열 형식으로 형식화됨
        var s = "Hello";
        Console.WriteLine("s : {0}, 타입 : {1}", s, s.GetType());

        // 배열 형식
        var numbers = new int[] { 1, 2, 3 };

        // 여기서 var item은 numbers 배열의 요소의 형식, 즉 int 형식임
        foreach (var item in numbers) 
        {
            Console.WriteLine("item : {0}, 타입 : {1}", item, item.GetType());
        }
    }
}
i : 5, 타입 : System.Int32
s : Hello, 타입 : System.String
item : 1, 타입 : System.Int32
item : 2, 타입 : System.Int32
item : 3, 타입 : System.Int32

변수 및 배열을 선언하자마자 동시에 초기화할 때에는 var 키워드를 사용할 수 있습니다. 이를 암시적으로 형식화된 로컬 변수 또는 배열이라고 합니다. var 키워드로 변수 또는 배열을 선언하면 자동으로 저장되는 값을 유추하여 해당 형식으로 초기화해줍니다.

요약

하나의 이름으로 여러 개의 데이터를 저장해 놓는 컬렉션 구조의 첫 번째인 배열(Array)에 대해 알아보았습니다. C#에서 배열, 리스트, 사전 데이터 형식은 매우 중요한 역할을 합니다. 잠시 함수를 알아보고 계속해서 C#의 여러 컬렉션 구조를 학습해 나가도록 하겠습니다.

정보처리산업기사 실기 시험 기출 문제 - 배열 초기화 및 데이터 할당

문제

다음 Java 프로그램이 실행되었을 때의 동작을 설명하고, 출력 결과를 예측하시오.

소스 코드 파일명: ArrayInitialization.java

public class ArrayInitialization {
    public static void main(String[] args) {
        int a[][] = new int[3][3];
        init(a);
        data(a);
        prnt(a);
    }
    static void init(int a[][]) {
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                a[i][j] = 0;
    }
    static void data(int a[][]) {
        int v = 1;
        for (int i = 0; i < 3; i++)
            for (int j = i; j < 3; j++)
                a[i][j] = v++;
    }
    static void prnt(int a[][]) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (a[i][j] == 0)
                    System.out.printf(" ");
                else
                    System.out.printf("%d ", a[i][j]);
                }
            System.out.println();
        }
    }
}

입력 예시

이 프로그램은 사용자로부터 입력을 받지 않습니다.

출력 예시

1 2 3 
  4 5 
    6 

정답

1 2 3
 4 5
  6

해설

이 프로그램은 3x3 크기의 2차원 배열을 초기화하고, 특정 패턴으로 데이터를 할당한 후 출력합니다.

  1. int a[][] = new int[3][3];는 3x3 크기의 2차원 정수 배열을 선언하고 모든 요소를 기본값인 0으로 초기화합니다.
  2. init(a); 함수는 배열의 모든 요소를 0으로 초기화합니다. (이는 사실상 불필요한 단계입니다, Java에서 새로 생성된 int 배열은 이미 0으로 초기화되어 있습니다.)
  3. data(a); 함수는 배열의 대각선을 기준으로 상단을 1부터 증가하는 값으로 채웁니다.
  4. prnt(a); 함수는 배열을 순회하며, 각 요소를 출력합니다. 0이 아닌 값은 해당 값과 함께 출력되고, 0인 값은 공백으로 대체하여 출력됩니다.

이 프로그램은 배열의 초기화, 데이터 할당, 그리고 조건에 따른 출력 방식을 보여주며, 2차원 배열을 다루는 기본적인 방법을 설명합니다.

VisualAcademy Docs의 모든 콘텐츠, 이미지, 동영상의 저작권은 박용준에게 있습니다. 저작권법에 의해 보호를 받는 저작물이므로 무단 전재와 복제를 금합니다. 사이트의 콘텐츠를 복제하여 블로그, 웹사이트 등에 게시할 수 없습니다. 단, 링크와 SNS 공유, Youtube 동영상 공유는 허용합니다. www.VisualAcademy.com
박용준 강사의 모든 동영상 강의는 데브렉에서 독점으로 제공됩니다. www.devlec.com