본문 바로가기

여러가지

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

드디어 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;


이렇게 하면 됩니다.