태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

[C/C++] 배열이야기

Posted on 2008.02.29 07:40
Filed Under Development


  • 이 글은 Jake 에 의해 www.jakeworld.net 에서 작성되었습니다.

  • 퍼가실 때는 이 박스와 함께 복사해주세요.

배열의 세부적인 메커니즘

1차원 포인터, 2차원 포인터... 등등은 각각 1차원 배열포인터, 2차원 배열포인터의 식별자들과는 타입이 전혀 틀립니다.

배열은 일반적으로 모두 1차원 포인터를 가진다는 이야기를 들었을 겁니다.

하지만 더욱 깊숙히 들어가면 내부적으로 배열의 식별자들은 배열이라는 별개의 타입을 가지고 있습니다. 대부분은 나중에 배열의 첫번째 요소를 가리키는 포인터로 "변환" 이 되어서 나오는거죠.


하지만 모든 상황에서 변환이 되는 건 아닙니다.

변환되지 않고 그대로 남아있는 경우는 다음과 같습니다.

(펀더멘탈C에서 참고 하였습니다)


*번지 연산자의 피연산자

*sizeof 의 피연산자 값으로 올때

*문자형 배열 초기화에 사용되는 문자열 상수


배열이 포인터로 변환되는 수많은 상황중 하나를 살펴보겠습니다.

int a[10]; 

이때 수식에서 a가 사용되면 a의 데이터형은 배열 타입이지만 포인터로 변환되게 됩니다.

그리고 변환된 포인터는 배열a의 첫번재 인덱스 a[0]를 가르키게 됩니다.

포인터로 변환된 배열은 더 이상 좌변값이 아닌 포인터 값일 뿐이며, 어떠한 경우에도 다시는 되돌아 갈 수 없다.

는 점이 중요합니다.


그럼 다음 수식이 나왔습니다.

*a = 0;  

당연하지만 결과적으로 a[0]에 0을 대입하게 됩니다. 어떻게 a[0] 로 변하는 건지 들여다 보겠습니다.

a가 포인터로 선언되어있다면 별 볼일 없는 구문이지만 a는 배열입니다. 위에서 이야기 한 3가지 예외에도 해당되지 않습니다.

결국 배열 a 는 첫번째 요소를 가르키는 포인터로 변환되게 됩니다.  a 자체는 &(a[0]) 형태로 변하는거죠.

그럼 *a 는 *(&(a[0]))  가 됩니다. *와 & 가 상쇄되어 a[0] 라는 결과가 나오게 되는거죠.


배열이 대입 연산자의 좌측 피연산자 (if: a=0;) 로 올 수 없는지도 설명이 되는거죠.

마찬가지로 배열은 포인터로 변환되지만 이 때 변환된 포인터는 좌변값이 아닌 값입니다.

대입연산자의 좌측 피연산자로는 좌변값 중에서도 특수한 조건을 갖춘 수정가능한 좌변값만 올 수 있는데 , 좌변값도 아닌 값이 주어져있으므로 잘못된 수식이 됩니다.  즉 이와 같은 결론으로

int a[10];
int b[10];
a = b; 

가 잘못된 수식이라는 것을 설명할 수 있습니다.

그리고 배열이 포인터 연산을 통해 가능한 이유도 설명이 됩니다. ^^




다차원 배열포인터와 다차원 포인터배열

배열 포인터와 포인터 배열에 대해서 구분을 확실히 하고 계신가요? ^^

2차원 이상의 배열포인터나 포인터 배열의 경우는 1차원과는 조금 틀린 형태를 뛰게 됩니다.


(x차원)배열포인터 : (x차원)배열을 가르키는 포인터

(x차원)포인터배열 : 포인터들을 지니고 있는 (x차원)배열


배열포인터와 포인터 배열의 생김새는 다음과 같습니다.

//배열포인터
int *Array;           //1차원
int (*Array)[10];     //2차원
int (*Array)[10][10]; //3차원
//포인터배열
int *Array[10];           //1차원
int *Array[10][10];       //2차원
int *Array[10][10][10];   //3차원 

포인터배열과 배열포인터를 이해하기에 쉬운방법은 다음과 같습니다.

1)
int (*Array)[10][5];
int Array2[20][10][5];

2) 
int *Array[10][5];  

* 배열포인터와 포인터 배열은 배열기호화 포인터기호 결합순서가 틀립니다.

1번의 배열포인터 경우 포인터(식별자)가 포인터기호와 먼저 결합후 배열기호화 결합되고,

2번의 경우 배열기호화 결합후 마지막에 포인터와 결합됩니다. (포인터 기호보다 배열 기호가 우선순위가 높습니다)

* 배열포인터의 포인터가 가르킬 수 있는 배열의 차원수는 자신의 뒤에 따르는 선언한 배열차원 + 1 차원입니다.

1번의 경우 (*Array) 가 아래쪽 선언에서 상위 인덱스 [20] 과 동등한 관계가 됩니다.

모든 배열포인터는 저런 관계를 지니게 됩니다.

그래서 다음과 같은 명령이 가능해집니다.

Array=Array2;


이런 관계를 인지하시면 다차원 배열포인터에 동적할당이 가능해집니다.


int (*Array)[10] = (int (*)[10])malloc(sizeof(int)*20); 
 


캐스팅 방식에 주의하시기 바랍니다.

배열식별자, 배열포인터 라는 존재가 일반적인 포인터와는 다르다는걸 직접적으로 보여주는 예 입니다.

Array 는 2차원 배열 포인터로서 Array에 대입할 수 있는 존재는 2차원 배열 식별자 혹은 2차원 배열포인터가 됩니다.

즉 int * 20 사이즈의 연속적인 공간을 할당받아 이 시작주소를 [x][10] 형태로 캐스팅하여서 2차원 배열포인터로 넣는 작업입니다.

결과적으로 Array[0][0] 부터 Array[1][9] 까지 총 20개의 영역을 사용할 수 있게 됩니다.

신고

댓글을 달아 주세요

About



모바일 페이지 QR 코드

Counter

· Total
: 468,854
· Today
: 92
· Yesterday
: 114


DNS server, DNS service