C/C++에서 포인터는 처음에 이해하기 어려운 부분 중에 하나입니다.

 

포인터때문에 C/C++에 흥미를 잃고 공부하기가 싫어지고는 합니다.

 

사실 포인터는 하나의 타입 그 이상도 이하도 아닙니다.

 

C를 처음 공부할 때 쓰는 scanf()를 사용할 때는 printf()와는 다르게

 

변수명에 &를 붙여주는 것을 기억하실 것입니다.

 

그리고 &가 주소를 나타낸다는 것도 다들  알것입니다.

 

포인터는 바로 이 주소를 저장하는 타입입니다.

 

변수는 메모리의 영역에 붙어있는 이름입니다.

 

변수가 선언되면 다음과 같이 메모리 영역이 확보가 됩니다.

 

 

int 형 변수를 하나를 선언하면 다음과 같이 4바이트가 할당이 됩니다.

 

포인터의 선언은 타입명* 변수명; 의 형태로 선언합니다.

 

포인터는 흔히 후라이팬과 손잡이로 표현이 많이 되곤합니다.

 

후라이팬 중심부는 실제 할당된 메모리로 보고,

 

포인터는 손잡이로 보는 것이죠.

 

일반적인 변수는 할당 시에 초기화를 하지 않으면 쓰레기 값을 갖게 됩니다.

 

이 쓰레기 값을 쓴다고 해서 프로그램이 죽거나 하는 일은 드믑니다.

 

int n;을 선언하고 화면에 출력하면 쓰레기 값이 출력될 뿐이지 프로그램이 죽진 않습니다.

 

하지만 포인터는 선언시에 들어 있는 쓰레기값으로 인해

 

프로그램이 죽을 확률이 아주 높습니다.(안 죽을 확률이 로또 1등될 확률보다 높을 지도...)

 

포인터가 메모리의 어느 지점을 가리키는데 쓰레기값이 들어 있으면 가리키는 곳이

 

현재 사용중인 프로세스가 할당한 곳인지, 아닌 지 알 수 없기 때문입니다.

 

그래서 보통 포인터형은 int* pI = NULL의 형태로 초기화를 해줍니다.

 

NULL 영역(Windows OS에서는 64K의 NULL 영역이 존재합니다.)을

 

가리키게 해주는 것입니다.

 

사실 포인터는 4바이트나 8바이트(64비트 OS의 경우)를 갖는 변수에 불과합니다.

 

그 곳에 메모리의 한 영역을 저장해 놓는 것 뿐이죠.

 

그래서 포인터는 기존에 프로세스가 할당해놓은 메모리나

 

새로할당되는 메모리를 가리키게 해야합니다.

 

int Index = 0;

int* pIndex = NULL;

pIndex = &Index;

 

이런 형식으로 사용해야 합니다.

 

pIndex는 주소값을 갖게 되고 Index의 주소값을 넣어주기 위해서 &Index로 한 것입니다.

 

(scanf에서는 그래서 &로 주소값을 넘겨줍니다. 변수로 넘겨주면 안에 값을 넣어도

 

함수를 빠져 나오면 아무 의미가 없어지기 때문입니다.

 

더 자세히 얘기하면 변수로 넘기면 함수 안의 변수는 넘겨주는 변수와 값만 같지

 

메모리 영역은 다르기 때문에 아무리 수정해놔도 원래 변수는 그대로인거죠.)

 

함수에서 포인터를 넘겨준다는 것은 효율성의 측면에서도 이득을 가져옵니다.

 

만약 구조체가 함수에 들어가야 한다면,

 

구조체를 통채로 넘기는 것보다는 포인터(4바이트나 8바이트일 뿐인...)를 넘겨주는 것이 유리하죠.

 

포인터(후라이팬 손잡이)를 쥐어줄테니

 

후라이팬에 있는 요리를 직접 요리(데이터의 수정 및 참조)해보라는 것이죠.

 

포인터는 일반적으로는 이런 형식으로 많이 사용됩니다.

 

MyStructType*pMyStruct = new MyStructType;

 

이렇게 사용하면 new 연산자를 통해서

 

메모리의 힙(동적 할당이 이루어지는 부분)부분 어딘가에 메모리가 생성이 되고

 

 

할당된 메모리의 시작번지만 포인터에 넣어주는 것입니다.

 

그럼 우린 이 포인터를 가지고 어디에 생성됐는지 몰라도

 

메모리 영역을 참조하고 쓰고할 수 있는 것입니다.

 

일반적으로 구조체나 클래스를 저런 식으로 동적할당할 때는

 

MyStruct->멤버변수 의 형태로 사용을 합니다.

 

물론 (*MyStruct).멤버변수의 형태로 사용도 가능합니다.

 

여기에서는 ()가 아주 중요합니다만(연산자의 우선순위 때문에...), 사실 저렇게는 잘 안씁니다.

 

일반적으로 프로그램이 죽는 경우는 이 포인터를 잘못 사용하기 때문에 발생합니다.

 

포인터가 사용되지 않을 때는 항상 NULL을 가리키게 해놓고

 

NULL일 때에 대한 예외처리만 확실하게 해준다면 이런 경우는 많이 줄어들 것입니다.

 

포인터는 프로세스가 할당한 유효한 메모리의 주소에만 유효합니다.

 

이것만 기억하면 프로그램을 잘 죽지 않게 만들 수 있습니다.

 

대부분의 메모리 할당(new, malloc, calloc, LocalAlloc등등...)은

 

메모리의 부족 등의 이유로 메모리 할당에 실패하면 NULL을 호출합니다.

 

메모리 할당 실패일 경우에 대한 예외처리도 확실하게 해두면

 

포인터의 잘못된 사용으로 프로그램이 죽거나 하지 않을 것입니다.

 

물론 메모리 할당에는 항상 해제가 뒤따라야 합니다.

 

new는 delete와 malloc은 free와 항상 짝이 맞아야합니다.

 

기본 타입 변수의 경우 *변수명은 포인터가 가리키는 곳의 정보(후라이팬)을 나타내고

 

변수명은 포인터 타입으로 선언된 그 자체(후라이팬 손잡이 = 포인터가 가리키는 곳의 주소)

 

를 나타냅니다.

 

즉, int A = 555; 이고 포인터 변수 int* pA = &A라고 할 때,

 

(A의 메모리 주소가 0x12345678이라고 가정)

 

*pA = 555이고, pA는 0x12345678 이 되는겁니다.

 

그 외에도 포인터 타입은 여러가지 특이점이 존재합니다.

 

포인터는 분명 사용하기가 까다롭기는 하지만, C/C++을 강력한 언어로 만들어주는

 

중요한 문법 중의 하나입니다.


출처 - http://blog.naver.com/PostView.nhn?blogId=psychoria&logNo=40125953503





Posted by linuxism
,