3.6. 배 열
변수가 단독주택이라고 할 경우 배열은 아파트나 빌라 정도에 해당하는 공동주택의 개념이라고 말씀드렸습니다. 그러므로 변수는 하나의 주소를 가지고 하나의 자료만 저장할 수 있지만 배열은 하나의 주소를 가지고 여러 개의 자료를 각기 다른 방에 저장할 수 있습니다. 배열의 선언이나 활용방법은 변수와 크게 다르지 않습니다. 그러나 아무래도 배열을 다루는 일이 변수를 다루는 일보다 힘듭니다. 그 까닭은 가지 많은 나무에 바람 잘 날 없는 것과 같습니다.
3.6.1. 배열의 선언와 정의
배열도 변수처럼 선언과 동시에 초기화할 수 있습니다.
배열도 변수처럼 선언과 동시에 초기화할 수 있습니다. 또 선언만 하고 초기화는 나중에 할 수 있습니다. 사용형식은 다음과 같습니다.
사용 형식
배열자료형이름 배열이름1[배열크기], 배열명2[배열크기], .....;
보기
int man[5], woman[10];
배열의 요소는 0번부터 시작한다는 점에 주의하기 바랍니다.
이때 주의할점은 배열의 요소는 0번부터 시작한다는 점입니다. 즉 man[0]번이 첫번째 배열요소이고, man[1]은 두번째 배열요소라는 점입니다. 배열을 사용하면서 가장 많이 착각하는 부분이 바로 배열의 순서입니다. 늘 다루면서도 잠깐잠깐은 man[2]가 두번째 칸이라는 착각을 합니다. 특히 피곤해서 정신이 몽롱할 때 이런 착각을 하기 쉽습니다. 물론 이런 착각 속에 프로그램을 짜면 전혀 엉뚱한 결과를 계산합니다. 배열을 사용하면서 가장 주의해야 할 부분은 바로 배열순서를 혼동하지 않고 정확하게 대입하는 일입니다.
배열은 요소 중 하나만 초기화시키면 됩니다.
배열은 모든 요소 중 하나만 초기화 되어도 경고가 발생하지 않으므로 적어도 하나만 초기화해두면 에러는 나지 않습니다. 그러나 자동배열은 성격상 자동변수처럼 함수 호출시 매번 초기화되므로 주의해야 합니다. 즉 자동배열의 경우 쓰레기값을 가지지 않도록 주의해야 합니다. 자동배열의 경우 배열요소 중 하나라도 초기화하면 나머지는 0을 가지는 특성이 있습니다. 정적배열이나 외부배열은 모든 배열요소가 0으로 자동초기화 됩니다.
**요약: 배열은 변수처럼 선언과 정의를 동시에 할 수 있습니다. 기억부류의 성질도 변수와 같기 때문에 자동배열일 경우에는 사용전에 한 번은 초기화를 해주어야 합니다.
3.6.2. 일차원 배열과 다차원 배열의 차이
배열은 변수와는 달리 다차원 구조를 가질 수 있습니다.
배열은 변수와는 달리 다차원을 가지고 있습니다. 이는 아파트 일 층에 열 가구가 살고 이층에도 열 가구가 사는 것으로 비유할 수 있습니다. 즉 배달아파트의 주소는 13번지라는 하나의 번지만 갖지만 10층 짜리 아파트라면 10층 몇 호라고 표시해야 우체부 아저씨가 우편물을 제대로 배달할 겁니다. 마찬가지로 1차원 배열은 배열아파트 101호 202로 나가는 주소라고 할 수 있고, 2차원 배열은 2층 101호, 3층 202호와 같이 나가는 아파트라고 볼 수 있습니다. 3차원 배열은 13동 2층 101호라고 할 수 있고 4차원 배열은 13동 2층 101호 내 온달 회사라고 할 수 있습니다.
다음의 형식과 보기로 이를 설명하겠습니다.
사용 형식
기억부류지정자 자료형이름 배열이름[][]... = ...}...}, 배열이름... ;
보기
int man[2] = {1, 2}; // 일차원 배열의 선언과 정의
int man[2][2] = 1,1}, {1,2 ; // 이차원 배열의 선언과 정의
int man[2][2][2] = { 1,1}, {1,2 , 1,1}, {1,2 ; 삼차원 배열의 선언과 정의
int man[2][2][3] = { 1,2,3}, {1,2,3 , 1,2,3}, {1,2,3},}; // 삼차원 배열의 선언과 정의
이때 배열의 크기가 생략된 경우에는 대충 알아서 컴파일러가 정합니다. 사용중인 배열의 크기를 알고 싶다면 'sizeof(배열명) / sizeof(배열요소형)' 명령을 이용해서 구할 수 있습니다. 초기치가 배열크기보다 많으면, 컴파일 할때 에러가 나지만 초기치가 배열의 크기보다 적으면 초기화되지 않은 배열요소는 0으로 초기화됩니다.
다차원 배열의 두번째 이후 배열요소의 크기는 생략하면 안됩니다.
다차원 배열의 경우 첫번째 첨자의 크기는 생략이 가능하지만, 두번째 이후의 첨자는 생략하면 안됩니다. 즉 첫번째 배열요소의 크기는 생략해도 되지만 두번째 배열요소의 크기는 생략하면 안됩니다. 배열요소의 크기는 다른 말로 해서 배열의 갯수라고 보면 됩니다. 즉 몇 층인가, 또 한 층에는 몇 개의 집이 있는가, 그 집에는 몇 개의 방이 있는가 등이 배열요소의 크기라고 생각하면 됩니다.
다차원 배열일 경우에는 선언과 동시에 초기화할 때 {}괄호로 묶어서 각 배열을 구분합니다. 이때 배열의 오른쪽 요소부터 먼저 묶어가면서 초기화하면 됩니다. 그리고 배열의 초기화 때는 하나의 배열요소만 초기화하고 나머지는 생략해도 됩니다. 그리고 마지막 배열요소를 다 초기화한 뒤에 여분으로 쉼표를 찍는데, 이것도 생략가능 합니다.
보기
int man[2][3] = 1,2,3}, {1,2,3},}; // 마지막 쉼표까지 찍음
int man[2][3] = 1,2,3}, {1,2,3 ; // 마지막 여분의 쉼표를 생략했음
int man[][3] = 1,2,3}, {1,2,3 ; // 첫번째 배열요소 크기 생략
int man[][3] = 1,,}, {1,2, ; // 배열요소 초기화 때 몇 몇 배열요소는 초기화 생략
배열은 배열이름과 요소를 지정해 참조할 수 있습니다.
이렇게 선언 정의된 배열을 참조할 때는 배열이름과 요소를 지정하는 것으로 참조할 수 있습니다.
// s06.cpp
#include
#include
void main(void){
int man[2][3] = 1,2,3}, {1,2,3},};
man[1][2]=9;
cout[[" 두번째-세번째 배열요소의 값은 "[[man[1][2][[" \n";
}
**그림: s06.cpp의 소스파일 내용
보기의 예제프로그램을 실행시키면 " 두번째-세번째 배열요소의 값은 9 "라는 문장이 화면에 출력되어 나올 겁니다.
**그림: s06.exe를 실행시켰을 때 나오는 화면
이번에는 다음과 같은 프로그램을 만들어 실행해봅니다.
// s07.cpp
#include
#include
void main(void){
int man[2][3] = 1,2,3}, {1,2,3},};
int a, b;
man[0][0]=7;
man[1][2]=9;
for(a=0;a<2;a++) {
for(b=0;b<3;b++)
{
cout[[a[["-"[[b[["배열의 값은 "[[man[a][b][[" \n";
}
}
}
**그림: s07.cpp의 소스파일 내용
위 예제를 실행시키면 다음과 같은 결과가 화면에 출력되어 나옵니다.
결과
0-0배열의 값은 7
0-1배열의 값은 2
0-2배열의 값은 3
1-0배열의 값은 1
1-1배열의 값은 2
1-2배열의 값은 9
**그림: s07.exe를 실행시켰을 때 나오는 화면
처음에 man을 초기화한 값은 이렇습니다.
0-0배열의 값은 1
0-1배열의 값은 2
0-2배열의 값은 3
1-0배열의 값은 1
1-1배열의 값은 2
1-2배열의 값은 3
그런데 man[0][0]에 7을 대입했고, man[1][2]에 9를 대입시켰기 때문에 예제프로그램의 결과처럼 배열의 값이 표시된 겁니다.
이제 배열을 어떻게 사용하는지 알 수 있을 겁니다. 다시 한 번 거듭 말씀드리지만 배열에서는 [0]이 첫번째 요소라는 점을 잊지 말아야 합니다. 이점만 유념하신다면 배열도 변수처럼 손쉽게 다룰 수 있습니다.
다차원 배열은 저장할 때 한 줄로 풀어서 저장합니다.
그럼 배열이 저장되는 모습을 알아봅시다. C++언어에서 배열은 옆으로 쭉 나열되는 형태도 저장됩니다.
보기
int man[2] = {1, 2};
기억장소에 저장되는 형태
배열요소
man[0]
man[1]
저장된 값
1
2
보기
int man[2][2] = 1,2}, {3,4 ;
기억장소에 저장되는 형태
배열요소
man[0][0]
man[0][1]
man[1][0]
man[1][1]
저장된 값
1
2
3
4
보기
int man[2][3] = 1,2,3}, {4,5,6 ;
기억장소에 저장되는 형태
배열요소
man[0][0]
man[0][1]
man[0][2]
man[1][0]
man[1][1]
man[1][2]
저장된 값
1
2
3
4
5
6
보기
int man[2][2][3] = {1,2,3}, {4,5,6 , 7,8,9}, {10,11,12 };
기억장소에 저장되는 형태
배열요소
man[0][0][0]
man[0][0][1]
man[0][0][2]
man[0][1][0]
man[0][1][1]
man[0][1][2]
저장된 값
1
2
3
4
5
6
윗줄에 옆으로 이어서
man[1][0][0]
man[1][0][1]
man[1][0][2]
man[1][1][0]
man[1][1][1]
man[1][1][2]
7
8
9
10
11
12
즉 위의 표를 옆으로 보기 좋게 표현하면 다음과 같습니다.
[0][0][0]
[0][0][1]
[0][0][2]
[0][1][0]
[0][1][1]
[0][1][2]
[1][0][0]
[1][0][1]
[1][0][2]
[1][1][0]
[1][1][1]
[1][1][2]
1
2
3
4
5
6
7
8
9
10
11
12
그러므로 다차원 배열을 너무 어렵게 생각할 필요는 없습니다. 다차원 배열이 어떻게 늘어나는지 그 구조를 다차원적인 도표로 그리면 다음과 같습니다.
보기
int man[2] = {1, 2};
옆으로 쭉 나열.
1
2
그림과 같이 일차원 배열일 때는 옆으로 쭉 나열하면 됩니다.
보기
int man[3][2]
1
2
1
2
1
2
일차원 배열을 밑으로 세번 복사한 것과 같음
이차원 배열 man[3][2]는 옆으로 나열한 배열을 다시 밑으로 세 번 나열하면 됩니다.
보기
int man[4][3][2]
man[3][2]를 옆으로 네 번 복사한 것과 같음.
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
삼차원 배열 man[4][3][2]은 이차원 배열을 다시 옆으로 쭉 네 번 나열하면 됩니다.
보기
int man[2][4][3][2]
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
밑으로 두 번 복사한 것과 같음
사차원 배열 man[2][4][3][2]은 man[4][3][2]라는 삼차원 배열을 다시 밑으로 쭉 두 번 나열하면 됩니다.
이처럼 배열은 한 차원이 늘 때마다 좌우나 위아래로 그 전차원의 배열을 담은 사각형 블럭을 복사하는 형태로 보면 됩니다. 그리고 실질적으로 저장할 때는 사각형으로 된 구조를 한 줄로 풀어서 저장하는 것이라고 보면 됩니다.
**요약: 다차원 배열은 이전 차원의 배열을 하나의 블럭으로 삼아서 계속 복사하는 형태입니다. 그러나 연속적인 메모리에 저장하므로 한 줄로 저장합니다. 배열을 저장할 때는 제일 오른쪽의 배열요소크기부터 기본 단위로 끊어서 저장합니다.