포인터

포인터 (Pointers)

값을 직접 다루는 대신, 값이 저장된 메모리 주소를 들고 다니는 변수도 있어요. 그게 바로 포인터예요. C에 익숙하다면 반가울, 여기서는 어떻게 선언하고 쓰는지 차근차근 볼게요.

출처: 문서

본문

Free Pascal은 포인터 사용을 지원해요. 포인터 타입의 변수는 다른 변수의 데이터가 저장될 수 있는 메모리의 주소를 담아요. 포인터 타입은 다음과 같이 정의할 수 있어요:

Pointer types
-> ^  type identifier

이 다이어그램에서 알 수 있듯이 포인터는 타입이 지정된(typed) 상태예요. 다시 말해 특정한 종류의 데이터를 가리켜요. 이 데이터의 타입은 컴파일 시점에 알아야 해요.

포인터를 역참조(dereference) 하면(변수 이름 뒤에 ^를 붙여서 표시) 그 결과는 마치 변수처럼 동작해요. 이 변수는 포인터 선언에 적힌 타입을 갖고, 포인터 변수가 가리키는 주소에 저장돼요. 다음 예시를 봐 볼게요:

Program pointers;

type

Buffer = String[255];

BufPtr = ^Buffer;

Var B  : Buffer;

BP : BufPtr;

PP : Pointer;

etc..

이 예시에서 BPBuffer 타입을 가리키는 포인터이고, BBuffer 타입의 변수예요. B는 256바이트 메모리를 차지하지만 BP는 4바이트(또는 8바이트)만 차지해요. 주소 하나를 저장할 수 있을 만큼이면 충분하니까요.

표현식

BP^

BP역참조라고 불러요. 그 결과 타입은 Buffer이므로,

BP^[23]

BP가 가리키는 문자열의 23번째 문자를 뜻해요.

주의: Free Pascal은 포인터를 C와 거의 비슷하게 취급해요. 즉 어떤 타입을 가리키는 포인터는 그 타입의 배열인 것처럼 다룰 수 있어요. 이 관점에서 보면 포인터는 배열의 0번째 요소를 가리켜요. 따라서 다음 포인터 선언은

Var p : ^Longint;

다음 배열 선언과 동등하다고 볼 수 있어요:

Var p : array[0..Infinity] of Longint;

차이는 전자가 포인터만을 위한 메모리를 할당하고(배열을 위한 메모리는 아님), 후자가 배열 전체를 위한 메모리를 할당한다는 거예요. 전자를 쓰면 Getmem 함수를 써서 메모리를 수동으로 할당해야 해요. P^ 참조는 곧 p[0]과 같아요. 다음 프로그램이 이 점을 더 명확히 보여줄 거예요:

program PointerArray;

var i : Longint;

p : ^Longint;

pp : array[0..100] of Longint;

begin

for i := 0 to 100 do pp[i] := i; { Fill array }

p := @pp[0];                     { Let p point to pp }

for i := 0 to 100 do

if p[i]<>pp[i] then

WriteLn ('Ohoh, problem !')

end.

Free Pascal은 C처럼 포인터 산술도 지원해요. 타입이 지정된 포인터 P에 대해,

Inc(P);

Dec(P);

은 각각 P가 가리키는 타입의 크기만큼 포인터가 가리키는 주소를 늘리거나 줄여요. 예를 들어

Var P : ^Longint;

...

Inc (p);

P를 4만큼 늘려요. 4가 longint의 크기이기 때문이죠. 포인터가 타입이 지정되지 않았다면 1바이트 크기로 가정해요(마치 ^byte 포인터인 것처럼).

포인터에는 일반 산술 연산자도 쓸 수 있어요. 다음은 유효한 포인터 산술 연산들이에요:

var  p1,p2 : ^Longint;

L : Longint;

begin

P1 := @P2;

P2 := @L;

L := P1-P2;

P1 := P1-4;

P2 := P2+4;

end.

여기서 더하거나 빼는 값은 포인터가 가리키는 타입의 크기와 곱해져요. 위 예시에서 P1은 16바이트만큼 줄어들고, P2는 16만큼 늘어나요.

더 알아보기