본문 바로가기

취업을 준비하며 정리하는 컴퓨터 지식/Data Structure

[Data Structure] 배열과 포인터

728x90

많은 프로그래밍 언어에서 배열은 따로 구현하지 않아도 사용할 수 있습니다. 그렇기 때문에 당연하게 배열을 사용하여 배열이 어떠한 의미를 가지는지 index를 넣으면 어떻게 값이 바로 나오게 되는지 고민해볼 시간이 많지 않았습니다. 따라서 다음의 목표를 기준으로 글을 작성해나가겠습니다.

 

  • 배열과 포인터의 특징과 의미가 무엇인지 알아본다.
  • 배열과 포인터는 어떠한 관계를 가지고 있는지 알아본다.

우선, 배열의 특징과 의미에 대해서 알아보겠습니다. 배열은 연속된 메모리 공간을 할당하여 값을 저장하는 방식으로 동일한 타입의 데이터를 저장할 때 사용합니다. 여기서 중요하게 봐야 할 부분은 연속된 메모리 공간과 동일한 타입의 데이터입니다.

 

연속된 메모리 공간은 배열이 저장되어 있는 메모리 사이의 빈 공간이나 배열과 관련 없는 값이 메모리를 차지 않았다는 것을 의미하고, 동일한 타입의 데이터는 배열의 각 요소가 차지하고 있는 메모리의 크기가 동일하다는 것입니다. 조금 더 쉽게 이해하기 위해서는 다음의 그림을 참고해주시기 바랍니다.

 

<배열의 메모리 할당 시각화>

연속된 공간과 같은 크기를 이용하면 index만 알면 해당 index의 값을 가져올 수 있습니다. list[0]번의 기본 주소를 base라고 하면 index에 따른 메모리 주소는 다음과 같이 가져올 수 있습니다.

 

배열 요소 인덱스 메모리 주소
List[0] 0 base + 0 * sizeof(int)
List[1] 1 base + 1 * sizeof(int)
List[2] 2 base + 2 * sizeof(int)
List[3] 3 base + 3 * sizeof(int)
List[4] 4 base + 4 * sizeof(int)
List[5] 5 base + 5 * sizeof(int)

만약 프로그래머가 배열의 세 번째 요소의 값을 가져오고 싶다면 컴파일러는 base + 2 * sizeof(int) 주소가 가리키는 값을 가져오게 됩니다.

 

만약 배열의 첫 번째 요소의 index가 1이라면 base + index * sizeof(int) 부분에 추가적인 연산이 들어가게 됩니다. 따라서 메모리 계산을 편하게 하기 위해서 많은 프로그래밍 언어들이 배열의 첫번째 요소의 index를 0으로 설정합니다.

 

다음은 포인터에 대해서 알아보겠습니다. 포인터는 다른 변수의 주소를 가지고 있는 변수를 뜻합니다. 다음의 코드를 예시로 설명해보겠습니다.

 

int num = 300;
int *p;
p = #

 

300이라는 정수를 저장한 num 변수의 주소를 포인터 변수 p에 저장하였습니다. 이 말은 *p와 num이 동일한 메모리를 참조하고 있다는 것입니다. 즉 p와 num은 값만 같은 것이 아니라 동일한 객체를 가리키고 있다는 뜻이므로 num의 변경은 p에 영향을 주고, p의 변경은 num에 영향을 주게 됩니다. 포인터에는 다음의 연산자들이 존재합니다.

 

  • & 연산자 = 주소 연산자
  • * 연산자 = 간접 참조 연산자

그렇다면 배열에서 포인터는 어떻게 사용될까? 배열의 이름에서 질문의 답을 찾을 수 있습니다.

 

배열의 이름 List에는 메모리 공간이 할당되지 않습니다. 대신에 배열의 이름이 있는 곳에 배열의 첫 번째 요소의 주소 base를 저장합니다. 이렇게 되면 배열의 이름은 포인터 변수가 되게 됩니다. 따라서 배열에서 포인터는 base의 주소를 저장되는 데 사용되게 됩니다.

 

참고자료 - c언어로 쉽게 풀어쓴 자료구조 (개정 3판) / 천인국, 공용해, 하상허 저 / 2019 / 생능출판사 

728x90