배열과 포인터(Pointer) 의 상관관계
이 글은 제가 과거에 운영했던 사이트인 http://dotnet.mkexdev.net 의 글을 옮겨온 것입니다. 원본 글은 2008년 5월일에 작성되었습니다.
그 전에 운영했었던 사이트(mkex.pe.kr)은 흔적도 없이 사라 졌습니다. 그속의 글들도 모두... 그래서 이 사이트도 사라지기 전에 옮기고 싶은 글을 조금씩 이 블로그로 이동시키려 합니다.
(원본글) http://dotnet.mkexdev.net/Article/Content.aspx?parentCategoryID=2&categoryID=9&ID=104
『 배열과 포인터(Pointer) 의 상관관계 』
배열은 포인터이다
대부분의 프로그래밍 언어에서는 배열이라는 복합 값을 다룰 수 있는 자료구조를 제공한다.
배열과 포인터는 내부적인 처리 방식이 거의 동일하다. 단 배열변수는 ‘상수 포인터’ 이다
일단 포인터의 내부 구조를 살펴 보자.
아래 샘플 코드는 int 형 변수를 가리키는 포인터를 생성해서 포인터를 통해서 i 의 값을 변경하는 예제이다.
void main(void){ int i = 1; int *p = &i; *p = 2; printf("%d",i); } |
시스템은 내부적으로 변수를 메모리에 저장하고 참조하기 위한 key-value 와 유사한 형태의 Symbol Table 라는 것을 관리한다. 이 Symbol Table 에는 변수명과 값이 저장된 메모리 주소 그리고 타입정보를 저장한다.
이것은 포인터도 마찬가지이다.
단, Symbol Table 에서 포인터는 자신의 타입정보 뿐만 아니라 포인팅하고 있는 대상의 타입정보도 같이 저장한다.
편의상 Symbol Table 가 다음과 같이 구성된다고 가정하자.
위의 예제를 Symbol Table 과 메모리 구조로 표현하면 다음과 같다.
int 형 변수 i 에 1을 저장했으므로 4byte 메모리 공간에 1을 저장하고 그 주소 값인 0x10 번지를 가리킨다.
그리고 i 의 주소 값을 포인팅 하는 포인터 변수 p 는 역시나 4byte 메모리 공간에 i 의 주소값인 0x10 을 저장하고
있는 0x100 번지를 가리킨다
즉 포인터 변수가 가리키는 메로리 공간에는 i 의 메모리 주소가 저장되어 있는 것이다(32 bit 시스템에서 메모리 주소 값은 4byte 로 표현되므로 포인터 p 는 4byte 의 메모리 공간을 차지하게
되는 것이다)
자.. 그럼 이제 배열을 알아 보자. 다음과 같이 선언된 배열이 있다고 가정하자.
int arr[] = {1,2,3}; |
이 배열을 Symbol Table 과 메모리 구조로 표현하면 다음과 같다.
배열 변수인 arr 은 배열의 첫 번째 요소(arr[0]) 를 포인팅 하는 별도의 상수형 메모리 공간인 것이다.
즉 arr 은 0x200 을 가리키고 여기에는 배열의 첫 번째 요소(arr[0]) 의 메모리 주소를 포인팅
하고 있는 것이다. 이 구조는 포인터와 완전히 동일한 구조이다.
실제로 이 배열을 정수형 포인터에 대입하면 포인터를 배열처럼 사용할 수 있다.
void main(void){ int arr[] = {1,2,3}; int *p = arr; printf("%d,%d,%d",p[0],p[1],p[2]); //1,2,3 이 출력된다 } |
단, int *p = arr 은 가능하지만 arr = p 는 성립하지 않는다.
앞서 말했듯이 arr은 상수이기 때문이다. 상수를 변경할 수는 없는 것이다.
또 하나, 일반적인 포인터에서 *p = 10 하면 p 가 포인팅 하고 있는 곳이 변경된다.
그렇다면 위의 배열 변수를 가지고 *arr = 10 하면 어떻게 되겠는가?
arr 은 배열의 첫 번째 요소를 포인팅하는 포인터이기 때문에 위의 식은 배열의 첫 번째 요소의 값을 변경하게 된다.
void main(void){ int arr[] = {1,2,3}; *arr = 10; printf("%d,%d,%d",arr[0],arr[1],arr[2]); //10,2,3 이 출력된다 } |
이로써 배열은 포인터 이다 라는 명제를 풀어 보았다.