혼자 연구하는 C/C++ 9장 정리(배열)

2015. 3. 1. 21:09창고

728x90
728x90
1. 배열

배열이란?

가장 기본적인 자료구조이다. 선형구조!

배열은 동일한 타입을 가지는 변수들의 유한 집합이다.

[ ] 괄호(bracket)와 배열 크기 지정문이 온다는 것만 다르다.

괄호가 하나 있으면 1차원 배열이고 두 개 있으면 2차원 배열이라 한다.


type 배열명[크기][크기]....;


type - 어떤 타입의 변수들이 모여 있는지를 지정한다.

배열명 - 배열의 이름. 명칭 규칙에 맞게만 작성하면 된다. 관습적으로 ar이나 a같은 접두어로 표현한다.

크기 - 몇 개의 요소를 가지는지, 즉 몇 개의 변수가 모여서 배열을 구성하는지를 지정하는데 자연수로 된 상수를 적어준다!


int ar[5];

배열을 구성하는 개별 변수들을 배열 요소(Element)라고 한다.

그림처럼 int ar[5]가 ar[0] ~ ar[4]까지 정수형 배열 요소 다섯 개가 동시에 생성된다.


자료구조에 비해 배열은 낭비되는 메모리가 없으며 배열 요소들이 연속적인 공간에 배치되어 있기 때문에

요소를 참조하는 속도가 대!단!히! 빠르다.

but, 연속적이어야 한다는 제약이 있어서 새로운 요소를 삽입하거나 기존 요소를 삭제하는 속도는 무척 느리다.


배열의 특징

- 배열 요소의 번호인 첨자는 항상 0부터 시작(zero base)한다.

- 배열이 차지하는 총 메모리양은 배열의 크기에 배열 요소의 크기를 곱해서 구할 수 있다.

1
배열 크기 = sizeof(배열)/sizeof(배열[0]); // 동일한 지역에서만!
cs

- 배열을 선언할 때 크기값은 반드시 상수로 주어야 한다.

- C언어는 배열의 범위를 전혀 점검하지 않는다.

ar[5]로 선언을 해도 ar[8]이 접근이 가능! 물론 정상적인 값이 아닐 가능성이 높다.

배열 요소의 범위를 벗어나는 경우 컴파일러가 점검을 할 수 있지만

범위를 점검하는 코드를 추가해야 하는데 이것은 실행 시간이 느려지게 한다.

배열은 신속한 요소 참조인데 이런 장점이 감소되기때문에 범위 검사를 하지 않는다!


다차원 배열

2차원 배열은 첨자 두 개를 사용하는 배열이다.


int ar[3][6];



메모리상에는 일직선으로 배열이 생성되지만 2차원 개념적으로 x,y 축을 가지는 평면이라고 생각해서 나온 그림이다.


배열의 기본 개념만 있다면 다차원 배열이라고 특별히 복잡한 것은 없다.

차원이 올라갈수록 메모리 요구량이 기하급수적으로 늘어난다는 점을 고려해야 한다!

int[100][100][100]은 메모리량이 무려 4M!


배열명

배열명이 단독으로 사용되면 배열의 시작번지값을 가지는 포인터 상수이다.

배열도 변수이므로 어딘가에 메모리를 차지하며 모든 배열 요소들이 연속적으로 배치되어 있다.

배열명은 이 메모리의 시작 번지를 가리키는 포인터가 된다.

물론 시작을 가리키는 포인터이되 배열이 선언될 때 메모리가 할당되므로 이 포인터는 변할 수 없는 상수값이다.

즉, 배열명은 포인터 변수가 아니라 포인터 상수!


1
2
3
4
int ar[5] = {1,2,3,4,5};
int ar2[5];
 
ar2 = ar;
cs


배열명은 포인터 상수기 때문에 좌변값이 될 수 없다! 그러므로 이 예제는 에러!


2. 배열 초기화

쓰레기값

배열을 함수 안에서 선언하면 지역변수가 되고 함수 밖에서 선언하면 전역변수가 된다.

기억장소나 통용 범위가 일반 변수와 같다.

파괴 시기나 초기화 여부도 일반 변수와 동일한데 그렇기 때문에 지역 배열은 초기화 되지 않는다.


컴파일러가 지역적으로 선언된 배열을 초기화하지 않고 내버려 두는 이유!

배열은 선언하자 마자 곧바로 어떤 값을 채워넣기 때문이다. 컴파일러가 실행 시간을 낭비해가며 참견할 필요가 없다.


1차 배열 초기화

배열을 선언할 때 초기값을 주는 방법도 일반 변수와 마찬가지다.


type 배열명[크기] = {초기화 값들};


ex)

1
int ar[5= {4,8,3,69,-7};
cs


배열 초기화 시 유의할 점

1
2
3
int ar[5= {4,8,3,69,-7};
int ar2[5];
ar2 = {1,2,3,4,5};
cs


1행에서 사용된 = 는 초기식에 사용되는 = 구두점이다.

3행에서 사용되는 = 는 연산자이다.

같은 모양을 하고 있지만 완전히 다른 동작을 하고 있다.

그러므로 3행과 같은 초기화는 할 수 없다.

배열 요소를 한꺼번에 대입할 수 있는 방법은 초기값을 주는 방법밖에 없다!


초기식

배열은 선언과 동시에 초기화할 때는 초기값의 개수가 배열 크기와 일치하는 것이 가장 이상적이다.


1
int arBig[1000= {1,2,3,0,0,0,0,0,................,0};
cs


하지만 이렇게 997개의 0을 써야 하는가?


1
int arBig[1000= {1,2,3};
cs


위 문장은 이렇게 간략하게 할 수 있다. 앞 부분만 1,2,3으로 초기화 되고 나머지는 모두 0으로 초기화한다.


모두 0으로 초기화 하는 방법은

1
2
int arBig[1000= {0};
int arBig[1000= {0, };
cs

이렇게 할 수 있다.


이렇게 초기화 하고 특정 부분만 값을 넣는 방법을 사용하면 된다.


1
int ar[5= {1,2,3,4,5,6};
cs


배열의 크기가 5인데 초기값이 6개가 주어졌다. 이 코드는 too many initializer라는 에러로 처리된다.


1
int ar[] = {1,2,3,4,5,6};
cs


초기식에 첨자를 생략하면 컴파일러가 필요한 배열의 크기를 지정한다.

6개의 int형으로 만들었으므로 4바이트씩 6개니깐 24바이트 만큼 자동으로 잡힌다.


2차 배열 초기화

- 초기값 개수가 꼭 맞는 경우

1
int ar[2][3= {1,2,3,4,5,6};
cs

요소별로 순서대로 대응하면 된다. 하지만 어디가 행인지 구분이 안되므로 초기값을 따로 묶어주는 방법이 있다.

1
2
3
4
5
6
int ar[2][3= {{1,2,3},{4,5,6}};
 
int ar[2][3= {
    {1,2,3},
    {4,5,6}
};
cs


- 초기값이 모자랄 때

1
2
3
4
5
6
7
8
9
10
11
int ar[2][3= {{1},{4,5,6}};
 
int ar[2][3= {
    {1,},
    {4,5,6}
};
 
int ar[2][3= {
    {1,0,0},
    {4,5,6}
};

cs


이런식으로 코드를 작성할 수 있다.



메모리 공간엔 그림처럼 들어가게 된다.

여기서 주의 할 점은 중괄호 없이 선언할 때 차이를 알아야 한다는 것이다.


1
int ar[2][3= {1,4,5,6};
cs



중간에 있는 행의 나머지 요소에 대한 초기값을 생략할 때는 행단위로 꼭 중괄호를 싸야한다!


- 초기값 개수가 남는 경우

too many initializer 에러가 된다.


- 배열의 크기를 생략하는 방법

2차원 배열도 생략이 가능하지만 1차 첨자의 크기만 생략이 가능하다. 나머지 첨자는 반드시 밝혀야 한다!

1
int ar[][3= {{1,2,3},{4,5,6}};
cs


728x90
반응형