본문으로 이동

미디어위키 1.45 안정화가 거의 끝났습니다. 다만 Flow 확장 기능 관련 이슈가 있어서 대체하는 작업을 수행할 계획입니다.

  1. 큰숲백과:청사진에서 위키 발전의 대략적인 방향성을 제시했습니다. 의견이 있으신 분은 큰숲백과토론:청사진에서 의견을 남겨주시면 좋겠습니다.
  2. 기능상의 오류로 지원하지 않고 있는 기능에 대해서는 큰숲백과토론:이슈 트래커에 요약했습니다. 참고하시기 바랍니다.
  3. 데이터베이스 덤프 받고싶으신 분은 큰숲백과 가입 후에 사용자토론:Bigforest에 의견 남겨주시면 ftp 주소, 계정, 비밀번호를 특수:EmailUser를 통해서 공개할 예정입니다.

작은숲:위키노트/초보자를 위한 C 언어 강의/포인터 연산

큰숲백과, 나무를 보지 말고 큰 숲을 보라.

포인터는 주소를 저장하는 변수이다. 이런 주소를 저장하는 포인터들도 연산을 할 수 있다. 하지만, 일반적인 값(정수, 실수, 문자)과는 연산하는 개념이 다르다. 이건 당연한 말일 것이다. 주소는 값이 아니기 때문이다. 항상 주소와 값은 구분해야 한다. 포인터 연산에는 크게 두 가지 종류가 있습니다.

  • 포인터 ± 정수 => 포인터
  • 포인터 - 포인터 => 정수

포인터 연산에서 먼저 생각해야 할 것은 포인터 연산은 '칸'으로 연산이 된다는 것이다. 여기에서 '칸'이라는 것은 데이터 형에 따라 달라진다. 즉, 데이터 형이 차지하는 메모리의 크기가 한 '칸'이 된다. 예를 들어, int 형의 경우 4 바이트만큼 차지할 테고, char 형의 경우 1 바이트를 차지한다. 따라서, int 형의 경우 한 칸은 4 바이트가 되고, char 형의 경우 한 칸은 1 바이트이다. 물론 각 데이터 형이 몇 바이트를 차지하느냐는 컴파일러나 OS, 시스템에 따라 달라진다. 이제 포인터와 정수의 연산을 생각해보도록 하자. 이 말은 주소와 정수를 연산하겠다는 말이다. 이 연산의 경우 덧셈과 뺄셈이 존재한다. 그리고 이 연산의 의미는 주소에서 몇칸 이동하라는 말이다. 간단한 예를 보도록 하자.

int *ptr = (int *) 1000;
ptr = ptr + 2;

첫번째 줄에서 1000이라는 정수를 형 변환 연산자를 사용해서 주소로 변환시켰다. 주소라는 것은 데이터 형이 포인터가 되야 하기 때문에 형 변환을 해줘야 한다. 앞에서도 말했지만 값과 주소는 구별해야 한다. int 형 포인터의 경우 그 데이터 형은 (int *)이다. 그런 다음 포인터 변수 ptr2를 더하고 그 값을 다시 ptr에 저장했다. 어떻게 될까? 포인터 변수 ptr에는 어떤 값이 저장되어 있을까? 답은 1008 번지이다. 정수 1008이 아니라 주소라는 것을 명심하시기 바란다. 왜 그럴까? 포인터 변수에 2를 더하라는 말은 현재 주소에서 두 칸 이동하라는 말이다. 따라서 이 포인터의 경우 데이터 형이 int 형 포인터이기 때문에 int 형으로 두 칸 이동하게 된다. 그것을 주소로 바꾸게 되면, int 형의 경우 한 칸이 4 바이트이기 때문에 (1000 + 8)이 된다. 만약 이 포인터 변수가 char 형 포인터 변수라면 답은 1002가 될 것이다. 이렇게 포인터와 정수의 연산은 "몇 '칸' 이동할 것인가"이다. 덧셈의 경우는 앞으로 이동하는 것이고, 뺄셈의 경우는 뒤로 이동한다. 따라서, 연산된 결과는 항상 주소가 나온다. 다음으로, 포인터와 포인터의 연산을 생각해보도록 하자. 포인터와 포인터의 연산은 곧 주소와 주소의 연산이다. 이 연산에서는 항상 뺄셈만 존재한다. 그리고 그 의미는 "연산자의 뒤에 나온 주소를 기준으로 했을 때 앞에 나온 주소가 몇 '칸' 떨어져 있느냐"입니다. 즉, 결과는 '칸'이 된며, 정수로 연산 결과가 나온다. 다음 예를 보자.

int *ptr1 = (int *) 1000;
int *ptr2 = (int *) 1400;
int i;
i = ptr1 - ptr2;

이 예에서 변수 i에 저장되는 값은 무엇일까? -400이라고 생각하기 쉬운데, 아니다. 정답은 -100이다. 물론 정수 -100이 변수 i에 저장된다. 왜 그럴까? 이유는 '칸'에 있다. 실제로 두 포인터를 정수라고 생각하고 연산을 하면 -400이 나온다. 하지만, 이것은 주소로서 -400이다. 포인터와 포인터의 연산의 결과는 '칸'이기 때문에 이 -400이라는 값을 포인터의 데이터 형, 즉 int 형의 크기로 나눠줘야 한다. 따라서 결과는 -100이 된다. 앞에서 말했지만 포인터와 포인터의 연산에서는 뺄셈만이 있다. 이것을 보통 offset을 구하는 연산이라고 말한다. 덧셈의 경우는 의미가 없다. 이것은 서울의 온도와 광주의 온도를 더하는 것처럼 아무런 의미가 없다. 그리고 포인터와 포인터의 연산에서 결과가 음수가 될 수 있는지 의문을 가질 수 있는데, 당연히 음수로 결과가 나올 수 있다. 포인터와 포인터의 뺄셈 연산은 두 포인터가 몇 '칸' 떨어져있는지를 구하는 것이기 때문에 음수가 나올 수 있는 것이다. 예를 들어, 그래프에서 10을 기준으로 했을 때 -10은 얼마나 떨어져있는가를 생각해보면 이해가 될 것이다. 기준점이 어디냐에 따라 값이 달라진다. 10을 기준으로 한다면 그 결과는 -20이 되겠지만, -10을 기준으로 한다면 결과는 20이 된다. 이렇게 포인터의 연산에서는 모든 것이 '칸'으로 결정된다. 따라서 포인터 연산을 할 때는 데이터 형이 굉장히 중요하다. 데이터 형에 의해 한 칸이 얼마인가가 결정되기 때문이다. 만약 데이터 형을 확실히 알지 못한다면, 포인터 연산의 결과를 제대로 찾을 수가 없다. 그리고 연산할 때는 항상 그 데이터 형을 맞춰줘야 한다. 고의로 하는 것이 아니라면, 반드시 데이터 형을 맞춰서 연산을 해야 제대로 된 결과를 볼 수 있다. 포인터 연산을 생각할 때는 가장 먼저 '칸'이라는 녀석을 머리 속에 떠올려야 한다. 그리고 포인터 연산에는 크게 두가지 종류가 있다는 것을 기억해야 한다. 또한 항상 주소와 값은 구별해야 한다. 이것만 주의한다면 포인터 연산도 쉽게 이해할 수 있을 것이다.

이 작은숲 문서의 출처는 위키노트의 위키노트: 문서입니다.