본문 바로가기

컴퓨터공학/C, C++

C,C++> 배열

배열은 낭비되는 메모리가 없으며 배열 요소들이 연속으로 공간 배치가 되어 있기 때문에 참조 속도가 빠르다.

그러나 요소를 삽입하거나 삭제하는 속도는 느린 단점이 있다. 

하지만 요즘은 컴퓨터 속도가 빠르기 때문에 크기가 지나치게 크지 않으면 큰 차이가 없다. 

C언어는 저수준 언어 특성상 배열을 많이 사용한다. 문자열조차 배열로 표현한다. 

 

배열 특징

1. 배열 요소 번호인 첨자는 항상 0에서 시작한다 

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

3. 배열 서언할 때 크기값은 상수로 주어야 한다.

4. C언어는 배열 범위를 점검하지 않는다.

배열 크기보다 큰 배열 요소를 작성해도 에러 처리가 안되고 컴파일이 잘 된다. 심지어 음수 첨자를 써도 컴파일이 잘 된다. 컴파일은 잘 되지만 정상 실행은 안 될 것이다. 왜 C 컴파일러는 배열 범위 점검을 하지 않을까? 컴파일러가 점검할 수 있는 경우는 첨자가 상수일 때이다. 첨자가 변수인 경우 범위를 점검하는 코드를 추가해야 하는데 매번 첨자 유효성을 일일이 점검하면 그만큼 실행 시간이 느려진다. 배열 강점은 속도인데 장점이 없어지는 것이다. 그래서 컴파일러는 배열 참조문에 아무런 처리를 하지 않는다. 배열 범위 점검은 개발자가 해야 한다. 

그리고 배열 크기가 5라고 해서 ar[8]이 포인터 측면에서 의미가 없는 것이 아니다. 

즉, 컴파일러가 책임지지 않은 대신 코드는 작고 빨라진다.

 

배열명 

배열명은 포인터 상수이다. 

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

배열명이 단독으로 사용된다는 말은 첨자없이 배열 이름만 적는다는 뜻이다. 배열명만 쓰면 배열 시작번지를 가리키는 포인터값이 된다. 예를 들어 str은 &str[0] 와 같은 표현이다. 배열이 선언될 때 메모리가 할당되므로 이 포인터는 변할 수 없는 상수값이다. 즉, 배열명은 포인터 변수가 아니라 포인터 상수이다. str은 시작 번지를 가리킬 뿐 다른 번지를 가리킬 수 없다.  포인터 상수값이지만 예외가 있는데 sizeof 연산자의 피연산자로 사용될 때는 배열 그 자체로 취급받아서 포인터 크기인 4를 반환하지 않고 배열 전체 크기를 반환한다. 

 

배열 초기화

배열은 정수형 변수나 실수형 변수와 동일한 변수이다. 기억 부류 지정자도 일반 변수와 동일하며 효과도 동일하다. 

 

1차 배열 초기화 

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

선언과 동시에 배열 초기화하지 않고 선언 후에 초기화 한다면 일일이 값을 대입하는 방법밖에 없다. 

예를 들어

int ar[5];

ar[0] = 4;

ar[1]= 2;

ar[2] = 4;

...

위의 배열 초기화 방법은 과정은 다르지만 결과는 동일하다.

첫 번째 = 기호는 변수 선언문과 초기값을 구분하는 구두점(Punctuator) 이고

두 번째 = 기호는 변수에 값을 대입하는 연산자(Operator)이다. 

= 구두점은 변수명과 초기값 구분을 할 수 없기 때문에 중간에 구분자를 넣은 것이다. 

반면 대입 연산자는 실행 중 우변 값을 좌변 변수에 대입한다. 

둘은 다르기 때문에 다음은 작동하지 않는다.

int ar[5];

ar = {4, 8, 3, 64,2};

배열 초기화에 사용되는 = 기호를 연산자라고 오해하면 선언한 다음 =로 배열 요소 전체를 한꺼번에 대입할 수 있다고 잘못 이해하게 된다. 따라서 배열 요소를 한 꺼번에 초기화할 수 있는 방법은 선언할 때 초기값을 주는 방법밖에 없다.

 

초기식

int ar[1000] = {1,2,3};

이렇게하면 앞 세 요소만 1,2,3, 으로 초기화하고 나머지는 0으로 초기화한다. 

지역 배열을 전역 배열처럼 초기화하고 싶다면 다음 둘 중 하나를 선택하면 된다. 

int ar[1000] = {0};

int ar[1000] = {0, };

배열 중간 부분을 0으로하고 뒷 부분만 원하는 것으로 초기화하는 방법은 존재하지 않는다. 

따라서 다음과 같이 한다. 

int ar[1000] = {0,};

ar[912] = 3;

전부 0으로 초기화하고 원하는 요소에 별도 대입했다. 

배열 크기가 5인데 초기값을 6개가 주어진다면 에러가 뜬다. 초기값이 모자라면 나머지를 0으로 초기화하지만 남을 경우 에러로 처리한다. 

다음처럼 배열 크기를 생략하면 자동으로 크기를 설정한다. 

int ar[] = {4,4,3,1,3};

 

2차 배열 초기화

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

다차원 배열은 메모리에 선형 연속 공간으로 생성되므로 초기값만 나열하면 등장하는 순서대로 배열 요소와 대응시킨다. 

그러나 초기값 나열 방식은 행 구별이 잘 안 되므로 다음처럼 행 별로 초기값을 묶어주는 방식이 더 좋다. 

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

 

초기값이 모자를 경우

특정 행 나머지 요소를 모두 0으로 초기화한다.

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

이렇게 하면 첫 행에는 초기값이 하나이므로 나머지 뒷 부분은 0이 되고 두 번째 행은 초기값이 있으므로 순서대로 초기화된다. 

 

초기값이 남을 경우

too many initializer 에러가 뜬다. 

 

배열 크기를 생략하는 방법

2차원 배열도 1차원 배열과 마찬가지로 배열 크기를 생략할 수 있다.  하지만 1차 첨자 크기만 생략 가능하다. 나머지 첨자는 반드시 밝혀야 한다. 

'컴퓨터공학 > C, C++' 카테고리의 다른 글

C,C++> 배열과 포인터  (0) 2022.07.19
C,C++> 포인터  (0) 2022.07.05
C,C++> 기억 부류  (0) 2022.06.08
C,C++> 함수  (0) 2022.06.06
C,C++> 조건문 제어문 연산자  (0) 2022.06.01