리루

[C언어]포인터 본문

# Algorithm

[C언어]포인터

뚱보리루 2017. 1. 4. 00:34

함수의 매개변수로서의 포인터


포인터는 C에서 함수 호출의 가장 중요한 부분이다. 가장 중요한 것은 참조 호출(Call-by-reference)이라는 매개변수 전달을 지원하기 위해 포인터가 사용된다는 점이다. 참조호출에서 함수가 전달된 매개변수를 변경했을 때 그 변경은 함수가 리턴한 후에도 지속된다. 매개변수 변경이 함수 내에서만 지속되는 값 호출(Call-By-Value)과 비교해 보라. 또 자료의 변경과 관계없이 많은 양의 자료를 함수에 전달하거나 함수에서 전달받을 때 포인터가 효율적인 수단이 된다. 전체 자료 대신에 포인터만 전달되므로 이 방법은 효율적이다.



참조 호출 매개변수 전달


형식적으로 C는 값 호출만 제공된다. 값 호출 매개변수 전달에서는 함수가 실행될 때 전달된 매개변수의 내부 복사본이 만들어져서 사용된다. 그러나 매개변수로 포인터를 전달함으로써 참조 호출을 흉내낼 수 있다. 이 방법을 사용하면 함수는 포인터의 내부 복사본을 얻는다. 


void swap1(int x, int y){


int tmp;

tmp = x;

x = y;

y = tmp;


return;

}


void swap2(int *x, int *y){


int tmp;

tmp = *x;

*x = *y;

*y = tmp;


return;

}



일반포인터와 캐스트


- C의 포인터 변수는 다른 변수들처럼 형을 갖는다는 점을 상기하자. 이에 대한 가장 큰 이유는 포인터를 해제할 때 가리켜지는 자료의 형을 컴파일러가 알고 적절히 접근할 수 있게 하기 위해서이다. 

- 그러나 때로는 포인터가 참조하는 자료의 형에 관심이 없을 때도 있다. 이 경우에 C의 형 시스템을 무시하는 일반 포인터(generic pointer)를 사용한다.


- 일반포인터에는 어떤 형의 포인터도 넣을 수 있고 그 역도 허용된다.

- C에서 일반 포인터를 만들려면 void 포인터로 선언한다.

- 예를들어, 메모리상의 한 위치의 자료 블록을 다른 곳으로 복사하는 표준 C라이브러리 함수 memcpy를 생각해보자. memcyp는 모든 형의 자료를 복사하는 데 사용되므로 포인터 매개변수가 무효 포인터인 것은 당연하다. 함수의 다른 형들을 좀 더 일반적으로 만들고자 할 때에도 무효 포인터를 사용한다.


#include <stdlib.h>

#include <string.h>


int swap2(void *x, void*y, int size){


void *tmp;


if((tmp=malloc(size)) == NULL)

return -1;


memcpy(tmp, x, size)

memcpy(x, y, size);

memcpy(y, tmp, size);


free(tmp);


return 0;

}


- void 포인터는 모든 형의 자료를 저장하고 조회할 수 있도록 하기 때문에 자료 구조를 구현할 때 특히 유용하다.



함수포인터


- 자료를 가리키는 대신에 실행 가능한 코드나 실행 가능한 코드를 호출하는데 필요한 정보 블록을 가리키는 포인터이다.

- 함수를 자료 조각들처럼 저장하고 관리하는데 사용된다.

- 함수 포인터의 한가지 중요한 용도는 함수들을 자료 구조에 캡슐화하는 것이다.


int (*match)(void *key1, void *key2);

retval = match(&x, &y);




Q&A

1. 다음 중 런타임 에러는?

 a)    char *sptr = "abc", *tptr;

 *tptr = sptr;


tptr가 문자를 참조할 때, sptr은 문자를 가리키는 포인터이므로 컴파일 에러가 발생한다. 따라서 이 코드는 문자에 문자 포인터를 지정하려고 하는 형 충돌이 발생한다.


b) char *sptr = "abc",*tptr;

   tptr = sptr;


tptr과 sptr이 모두 문자 포인터이므로 아무런 오류도 발생하지 않는다.


c) char *sptr = "abc", *tptr;

   *tptr = *sptr;


tptr에 기억장소가 할당되지 않았으므로 런타임에러가 발생할 수 있다. tptr을 해석할 떄 그것이 어디를 가리키는지 확실할 수 없다.


d) int *iptr = (int *)10;

   *iptr = 11;


정수 포인터에 고정된 주소를 지정하는 것은 위험하므로 실행 시간 오류가 발생할 수 있다. iptr을 해석할 때 주소 10에 11을 쓰려고 하는데 이것은 아마더 정당하지 않을 것이다.


 e) int *iptr = 10;

    *iptr = 11;


이 코드는 정수 포인터를 정수로 초기화하려고 하는데 이것은 형 충돌이므로 컴파일 에러나 경고가 발생한다.


f) int *iptr = (int *) 10;

   iptr = NULL;


이 코드는 처음에 iptr을 고정된 주소로 초기화하는 위함헌 단계를 수행하지만 곧 NULL로 고쳐지는데 이것은 정당하므로 아무런 오류가 발생하지 않는다.

'# Algorithm' 카테고리의 다른 글

[자료구조] 해시 테이블  (0) 2017.01.15
[자료구조] 집합(set)  (0) 2017.01.12
[C언어] 재귀  (0) 2017.01.05
[C언어] 메모리 영억  (0) 2017.01.05
자료구조 & 소프트웨어 공학 소개  (0) 2017.01.03