여러가지

기말고사 대비 프기실 4강. Pointer

운영인 2014. 12. 16. 01:38

드디어 4강입니다. 수고하셨습니다.


많은 분들이 포인터를 어려워 한다고 들었고 그렇게 생각합니다.


하지만 저는 포인터가 전혀 어렵지 않다고 생각합니다.


지레 겁먹지 말고 보세요. 진짜 쉽다니까요?


int a = 1;

int *p;

p = &a;

printf ("%d",p);

printf ("%d",*p);

*p = 2;


위에 코드를 봅시다. a라는 변수를 만들고 1로 만들었습니다.


int *p라는 것이 포인터입니다. int *b 이런식으로 포인터를 만드는 거죠.


그리고 만든 포인터에 a의 주소값을 넣습니다. (&a)


처음 프린트되는건 뭘까요, 당연히 p에다가는 a의 주소를 넣었으니 a의 주소가 나오겠죠.


그 다음 프린트 되는건? 1이 나옵니다. * 라는 기호가 p에 있는 주소값에 가라는 의미입니다.


*p = 2;도 마찬가지로 *이 저장된 주소에 가란 소리니까 a가 2로 바뀌게 됩니다.


여러분이 헷갈려 하시는건 이 부분 입니다.


포인터를 선언할때 int *p;의 *와, 그 다음에 쓸때 *는 완전히 다른겁니다.


기호만 같을 뿐, 같은 역할이 아니죠.


int *p;의 *는 포인터를 만든다, 라는 의미이고, *p  = 1;할때 *는 저장된 주소로 가라, 라는 의미이죠.


그런데 아주 헷갈릴만도 할것이,

int *p;

p = &a;

를 합쳐서 int *p = &a; 라고 쓸 수 있다는 겁니다.


당연히 a의 주소값은 p에다가 넣어야죠. p = &a;가 맞습니다.


그냥 두 문장을 합칠때만 그렇게 쓴다는걸 알아둡시다. 


포인터의 개념은 이게 끝입니다. 정말로요.


이제는 포인터를 쓰는 다른 방법을 알아봅시다.


예전에 어레이를 만들때 arr[5] 를 만들었으면 왜


arr[0], arr[1], arr[2], arr[3], arr[4]


가 만들어 지듯이 왜 0부터 만들어지나 궁금했을 겁니다.


어레이에 포인터를 줘 봅시다.


int arr[5] = {1,3,5,7,9};

int *p;

p = arr;


저번 어레이에서 arr 과 &arr[0]은 같다고 배웠죠? 이거 모르면 큰일입니다. 정말.


*p를 하면 뭐가 나올까요? 1이 나옵니다. arr[0]의 주소를 줬으니까요.


어레이의 장점은 쉽게 만들고 쓸 수 있다는 점 뿐만 아니라 주소상으로도 연결 되있다는 점입니다.


*(p+1) 은 3이 나오게 됩니다. arr[1]과 똑같죠.


(p+1)이 뭘까요? p에는 arr[0]의 주소가 입력되어있죠. 거기에 1을 더한겁니다.


우리가 포인터를 처음 만들때 int *p라고 만들었죠. int를 표기할 포인터를 만든겁니다.


int *p는 1을 더하면 int에 맞춰서 자동으로 다음 1칸 옆으로 이동합니다.(4바이트 옆)


char *p라고 하면 1바이트 옆으로 이동하겠죠. 예를 들어 name[0] 에서 name[1]로 넘어가죠.


위 코드에서 *(p+1)은 arr[1]과 같습니다. 그래서 어레이가 0부터 시작되는거죠.


*(p+1)이라 치기 귀찮다면 그냥 p[1]이라 쳐도 됩니다. 이걸 컴파일러가 *(p+1)이라 인식하죠.


이러고 보니 포인터와 어레이가 참 비슷하지 않습니까?


사실 엄청 비슷합니다. 다른점은 어레이는 처음 만들어질때 크기가 정해져있고 주소를 못바꾼다는 점이죠.


사실상 같은 개념으로 생각해도 괜찮습니다.




이제 펑션에서도 포인터를 사용해 볼까요?


void square (int *p)

{

*p = (*p)*(*p);

}


int main()

{

int a = 3;

square (&a);

printf ("%d",a);

....



펑션에 있는 int *p는 square(&a)를 받았으니 p = &a;입니다.


어레이랑 마찬가지로 주소값을 받았으니 직접 수정이 가능하죠.



지금부터는 좀 이해하기 싫어질 겁니다. 점수를 좀 더 잘 받고싶으면 봅시다.


어레이를 100개, 1000개, 10000개 이렇게 만들다 보면 상당한 메모리가 필요합니다.


쓴 메모리는 지울 수 없을까요?


아예 처음부터 다이나믹 메모리를 할당합시다. <stdlib.h> 가 필요합니다.


int *p = (int*)malloc(4);


이러면 4바이트가 만들어지고 p가 그걸 가리키고 있네요.


(int*)malloc(sizeof(int)*8);


sizeof(int) 는 int 의 사이즈입니다. sizeof(char) 이런식으로도 가능하죠.


int 8개를 만들었으니 p[8]을 선언한것이랑 똑같습니다.


이렇게 잘 사용하고 난뒤 다른 데이터를 위해 이 메모리를 없애줘야겠죠?


free(p);


free(*p)가 아닙니다. free(p)라고 쓰면 아까 선언한 sizeof(int)*8이 없어집니다. 메모리 상에서요.


그 다음 포인터 p가 가르키고 있는것을 없애줘야 합니다. 포인터가 엉뚱한데를 가르키고 있으면 위험하거든요.


p = NULL;


이렇게 하면 됩니다.