..

Search

23) 1차원 배열

23) 1차원 배열

1차원 배열


배열(array)이란?

배열(array)은 같은 타입의 변수들로 이루어진 유한 집합으로 정의할 수 있습니다.

배열을 구성하는 각각의 값을 배열 요소(element)라고 하며, 배열에서의 위치를 가리키는 숫자를 인덱스(index)라고 합니다.

C++에서 인덱스는 언제나 0부터 시작하며, 0을 포함한 양의 정수만을 가질 수 있습니다.

 

배열은 같은 종류의 데이터를 많이 다뤄야 하는 경우에 사용할 수 있는 가장 기본적인 자료 구조입니다.

 

배열은 선언되는 형식에 따라 1차원 배열, 2차원 배열뿐만 아니라 그 이상의 다차원 배열로도 선언할 수 있습니다.

하지만 현실적으로 이해하기가 쉬운 2차원 배열까지가 많이 사용됩니다.


1차원 배열

1차원 배열은 가장 기본적인 배열로 다음과 같은 문법에 따라 선언합니다.

문법

타입 배열이름[배열길이];

 

타입은 배열 요소로 들어가는 변수의 타입을 명시합니다.

배열 이름은 배열이 선언된 후에 배열에 접근하기 위해 사용됩니다.

배열의 길이는 해당 배열이 몇 개의 배열 요소를 가지게 되는지 명시합니다.

 

열은 선언만 하고 초기화하지 않으면, 모든 배열 요소가 쓰레깃값으로 채워집니다.

 

예제

int sum = 0;

int grade[3]; // 길이가 3인 int형 배열 선언

 

// 인덱스를 이용한 배열의 초기화

grade[0] = 85; // 국어 점수

grade[1] = 65; // 영어 점수

grade[2] = 90; // 수학 점수

 

for (int i = 0; i < 3; i++)

{

    sum += grade[i]; // 인덱스를 이용한 배열로의 접근

}

 

cout << "국영수 과목 총 점수 합계는 " << sum << "점이고, 평균 점수는 " << (double)sum/3 <<"점입니다.";

코딩연습 ▶

실행 결과

국영수 과목 총 점수 합계는 240점이고, 평균 점수는 80점입니다.

 

위의 예제는 int형 데이터를 3개 저장할 수 있는 배열을 선언하고 있습니다.

또한, 0부터 시작하는 인덱스(index)를 이용하면 각각의 배열 요소에 따로 접근할 수 있습니다.

 

다음 그림은 위의 예제에서 사용된 배열 grade가 메모리 상에서 어떻게 저장되는지를 보여줍니다.

 

 

위의 그림처럼 언제나 배열의 이름은 배열의 첫 번째 요소와 같은 주소를 가리키고 있습니다.


배열의 선언과 동시에 초기화하는 방법

C++에서는 변수와 마찬가지로 배열도 선언과 동시에 초기화할 수 있습니다.

다음과 같이 괄호({})를 사용하여 초깃값을 나열한 것을 초기화 리스트라고 합니다.

문법

타입 배열이름[배열길이] = {배열요소1, 배열요소2, ...};

 

단, 초기화 리스트의 타입과 배열의 타입은 반드시 일치해야 합니다.

만약 초기화 리스트의 개수가 배열의 총 길이보다 적으면, 배열의 앞에서부터 차례대로 초기화될 것입니다.

이때 초기화되지 못한 나머지 배열 요소는 모두 0으로 초기화됩니다.

초기화 리스트의 개수가 배열의 길이보다 많을 경우에는 아래 배열의 특징에서 따로 다루도록 하겠습니다.

 

하지만 초기화 리스트를 이용한 초기화 방식은 반드시 배열의 선언과 함께 정의되어야 합니다.

배열이 먼저 선언된 후에는 이 방식으로 배열의 요소를 초기화할 수 없습니다.

예제

int arr1[3] = {0, 1, 2}; // 배열의 선언과 동시에 초기화는 가능함.

int arr2[3];             // 배열의 선언

arr2[3] = {0, 1, 2};     // 배열이 먼저 선언된 후에는 이 방식으로 초기화될 수 없음. 오류가 발생함.

arr2 = arr1;             // 길이가 같더라도 하나의 배열을 다른 배열에 통째로 대입할 수는 없음. 오류가 발생함.

 

다음 예제는 앞선 예제와 같은 배열을 선언과 동시에 초기화 리스트로 초기화하는 예제입니다.

예제

int sum = 0;

int grade[3] = {85, 65, 90}; // 길이가 3인 int형 배열의 선언과 동시에 초기화

 

for (int i = 0; i < 3; i++)

{

    sum += grade[i]; // 인덱스를 이용한 배열의 접근

}

 

cout << "국영수 과목 총 점수 합계는 " << sum << "점이고, 평균 점수는 " << (double)sum/3 <<"점입니다.";

코딩연습 ▶

실행 결과

국영수 과목 총 점수 합계는 240점이고, 평균 점수는 80점입니다.


배열의 길이 자동 설정

C++에서는 초기화 리스트에 맞춰 자동으로 배열의 길이를 설정할 수도 있습니다.

문법

타입 배열이름[] = {배열요소1, 배열요소2, ...};

 

배열의 길이를 따로 입력하지 않은 배열은 초기화 리스트의 배열 요소 개수에 맞춰 자동으로 배열의 길이가 설정됩니다.

 

예제

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

 

위의 예제에서 int형 배열 arr의 길이는 자동으로 3으로 설정됨과 동시에 초기화 리스트에 의해 초기화됩니다.


배열의 특징

C++에서 배열은 다음과 같은 특징을 가집니다.

 

1. 배열의 길이를 선언할 때에는 반드시 상수를 사용해야 합니다.

2. 배열 요소의 인덱스는 언제나 0부터 시작합니다.

3. C++ 컴파일러는 배열의 길이를 전혀 신경 쓰지 않습니다.

 

예제

int sum = 0;

int grade[3] = {85, 65, 90}; // grade[0], grade[1], grade[2]만 선언 및 초기화

grade[3] = 100;              // grade[3]를 선언하지 않고 초기화 진행

 

for (int i = 0; i < 4; i++)  // grade[3]도 수식에 포함

{

    sum += grade[i];         // 인덱스를 이용한 배열의 접근

}

 

cout << "국영수 과목 총 점수 합계는 " << sum << "점이고, 평균 점수는 " << (double)sum/3 <<"점입니다.";

코딩연습 ▶

실행 결과

국영수 과목 총 점수 합계는 340점이고, 평균 점수는 113.333점입니다.

 

위의 예제에서는 길이가 3인 int형 배열 grade를 선언하고 있습니다.

즉, 배열 grade의 배열 요소는 grade[0], grade[1], grade[2]만이 존재합니다.

하지만 존재하지도 않는 grade[3]이라는 배열 요소의 초기화를 진행하고, 반복문을 통해 수식에서도 이용합니다.

 

이때 C++ 컴파일러는 오류는 커녕 수식에서까지 이 배열 요소를 이용하여 결과까지 출력해 줍니다.

하지만 이 결과는 개발자가 전혀 의도하지 않은 결과물이며, 이러한 프로그램은 종종 예상치 못한 결과를 내주기도 합니다.

 

위처럼 C++에서는 컴파일러가 일일이 배열의 길이 등을 검사하여 오류를 출력해 주지 않습니다.

따라서 C++로 프로그래밍할 때에는 언제나 이런 계산을 개발자가 직접 해주어야 합니다.


배열이 차지하는 메모리의 크기

C++에서 배열을 복사하거나 배열 요소에 특정 작업을 하고 싶을 때는 해당 배열이 차지하는 메모리의 크기를 정확히 알고 있는 것이 좋습니다.

 

배열이 차지하는 총 메모리의 크기는 다음 수식을 사용하여 구할 수 있습니다.

수식

배열이 차지하는 메모리의 크기 = 배열의 길이 X sizeof(타입)

 

그리고 배열의 길이를 알고 싶을 때에는 다음 수식을 사용하여 구할 수 있습니다.

수식

배열의 길이 = sizeof(배열 이름) / sizeof(배열 이름[0])

 

위의 수식에서 배열 이름[0]은 해당 배열의 타입을 나타내기 위해서 사용되었습니다.

 

예제

int grade[] = {85, 65, 90};                 // 배열의 길이를 명시하지 않음

int len = sizeof(grade) / sizeof(grade[0]); // 배열의 길이를 구하는 공식

 

cout << "배열 grade의 길이는 " << len << "입니다.";

코딩연습 ▶

실행 결과

배열 grade의 길이는 3입니다.


C++11에서의 배열 초기화

C++11에서는 배열의 초기화에 관해 다음과 같은 사항들이 변경되었습니다.

 

1. 배열을 초기화할 때에 대입 연산자(=)를 사용하지 않아도 됩니다.

2. 값을 명시하지 않고 괄호({})만을 사용하여 초기화하면, 모든 배열 요소를 0으로 초기화할 수 있습니다.

3. 초기화 리스트를 사용하여 배열을 초기화할 경우에는 narrowing cast를 할 수 없습니다.

4. array 템플릿 클래스가 추가되었습니다.


narrowing cast

이전 버전의 C++에서 발생하던 수많은 호환성 문제를 C++11에서는 초기화 리스트를 사용하여 방지할 수 있습니다.

C++11에서는 초기화 리스트를 사용하여 변수나 배열을 초기화할 경우에 narrowing cast를 허용하지 않습니다.

따라서 초기화 리스트를 이용한 초기화에서 narrowing cast가 발생하면, 경고(warning)를 발생시킵니다.

 

narrowing cast란 다음 예제와 같이 초기화를 통해 발생하는 암시적인 데이터의 손실을 의미합니다.

예제

int var = 3.14// narrowing cast

 

위의 예제는 int형 변수를 실숫값으로 초기화함으로써 데이터의 손실이 발생합니다.

이렇게 데이터의 손실이 발생하는 암시적인 타입 변환을 narrowing cast라고 합니다.

 

C++11에서는 초기화 리스트를 이용하여 이러한 narrowing cast로 인한 데이터의 손실 및 호환성 문제를 미리 방지할 수 있습니다.

예제

int var = {3.14}// 초기화 리스트를 통한 narrowing cast는 허용하지 않으므로, 경고를 발생시킴.


연습문제