Programming Language/C/C++

[C/C++] 포인터 pointer

깐요 2017. 2. 26. 14:11

포인터?

포인터(Pointer)는 다른 변수의 주소를 가리킨다

포인터 변수를 선언하기 위해서는 * 연산자를 사용하여 선언한다

포인터 변수에 다른 변수의 주소를 대입하기 위해서는 & 연산자를 사용한다


char a = 'A';
char *p;
p = &a;

'A' 라는 값을 가진 char형 변수의 주소는 26 이다

char형 변수의 주소를 가리키는 포인터는 26 의 값을 가지게 된다


*p = 'A'    a = 'A'

&a = 26    p = 26


여기서 *p 의 값을 바꾸게 되면 어떻게 될까?


*p = 'B';

위 코드를 실행하면 a 의 값이 'B' 로 바뀌게 된다

*p 와 변수 a 는 동일한 객체(상자)를 가리킨다

즉, *p 와 a 는 완전히 동일하다

동일한 객체를 가리키기 때문에 한 쪽의 값을 바꾸게 되면 다른 한 쪽의 값도 똑같이 바뀌게 된다


포인터는 char 형 뿐만이 아니라 다양한 타입으로 선언해줄 수 있다

void, float, char, int, struct 등등

함수의 포인터도 만들 수 있다


void (*f)(int);

f 는 int 형 변수를 매개 변수로 갖고 반환 값을 가지지 않는 함수를 가리키는 포인터다


포인터는 왜 쓰일까?

함수가 동작하기 위해서는 경우에 따라 변수를 전달받기를 요구한다

이때 전달하는 방법이 값으로 전달하는 것과 주소를 전달하는 것 2가지가 있다

전달하고자 하는 변수의 크기가 작다면 둘의 차이는 크지 않다

반면 변수의 크기가 클 경우에는 이야기가 달라진다

값으로 전달하게 되면 똑같은 변수를 복사하는 데 시간이 걸리고, 기억 장소에대한 요구도 높아진다

이는 시스템 성능 저하로 연결된다


꼭 위와 같은 상황말고도 C에서는 값으로 전달하는 것을 혀용하지 않는 경우가 있다

가장 대표적인 Swap 함수를 예시로 사용해보겠다

Swap 함수는 참조한 두 개의 변수의 값을 서로 바꾸는 함수이다


void Swap(int x, int y)
{
    int tmp;
    tmp = x;
    x = y;
    y = tmp;
}
 
main()
{
    int a, b;
    a = 10, b = 20;
    Swap(a, b);
}

위 코드의 결과는 어떻게 될까?

답은 '아무런 변화가 없다'이다


포인터를 사용하지 않고 작성한 Swap 함수를 실행하면

각 변수 a, b 의 값은 다른 int 형 변수에 복사된 후에 서로 교환하게 된다

따라서 원본은 전혀 변화가 없게 된다


그림으로 표현하면 다음과 같다

main 에서 10 20 을 Swap 함수에 참조해준 후

각각 바뀐 20 10 이 main 함수로 전달되지 못한 상황이다

이러한 방식을 Call by Value 라고 부른다


하지만 다음과 같이 포인터를 참조하게 되면 상황이 달라진다


void Swap(int *px, int *py)
{
    int tmp;
    tmp = *px;
    *px = *py;
    *py = tmp;
}
 
main()
{
    int a, b;
    a = 10, b = 20;
    Swap(&a, &b);
}

&a &b 를 참조하면서 a 와 b 의 주소값을 Swap 함수 px 와 py 에 전달한다

즉, *px = &a    *py = &b 와 같은 효과가 나타난다

함수에서 *px 와 *py 의 값이 바뀌므로 a 와 b 의 값도 바뀌게 된다

이러한 방식은 Call by Reference 라고 부른다


위 방식을 이용하면 하나의 함수에서 2개의 값을 반환할 수도 있다

하나의 함수에서 2개의 점의 좌표를 받아서 기울기와 y절편을 구하는 함수는 어떻게 만들까?


구조체에서의 포인터

이전 포스트에서 구조체에 대해 다뤘다

구조체의 멤버에 접근할 때는 항목 연산자 '.' 을 사용한다


구조체의 포인터로 멤버에 접근하기 위해서는 '->' 를 사용한다


struct {
    int i;
    float f;
} s;
 
struct s *ps;
 
ps = &s;
 
ps->i = 2;        
(*ps).i = 2;      //같은 표현이다

포인터의 포인터

포인터의 포인터를 선언할 수도 있다


char a;
char *p;
char **pp;
a = 'A';
p = &a;
pp = &p;


포인터 연산

포인터도 연산이 가능하다

단, 포인터는 변수의 주소의 값을 가지므로 연산의 의미가 달라진다

다음 그림을 참고하자



int 형 배열에서 A[2] 의 주소를 가리키는 p 가 있다고 가정하자

p + 1 은 주소 값이 하나 증가되는 것이 아니라 p 가 가리키는 객체의 하나 앞에 있는 객체를 가리킨다


p         //포인터
*p        //포인터가 가리키는 값
*p++      //??
--*p      //??
(*p)++    //포인터가 가리키는 값을 증가시킨다


포인터와 NULL

포인터가 어떤 값을 가리키고 있지 않을 때는 항상 NULL 로 설정하는 것이 옳다

포인터가 초기화가 되지 않은 상태에서 포인터가 가리키는 곳에 자료를 저장하면 오류가 발생할 수 있다

320x100

'Programming Language > C/C++' 카테고리의 다른 글

[C/C++] strlen 함수, 문자열의 길이  (0) 2017.04.20
[C/C++] fflush 함수  (0) 2017.03.10
[C/C++] 동적 메모리 할당 malloc  (0) 2017.02.27
[C/C++] 구조체 struct  (0) 2017.02.25
[C/C++] 순환, 재귀 호출  (0) 2017.02.19