티스토리 뷰

오랜만에 C와 C++ 공부를 다시 시작하게 되면서 그동안 쓸 일이 없었던 Pointer의 개념을 다시 정리해보려 한다. 하나의 scope 안에서 변수의 값을 초기화하고 변경하는 경우에는 아무런 문제가 없겠지만, 함수를 사용하는 과정에서 영구적으로, 혹은 완벽하게 해당 변수의 값을 변경하려고 한다면 반드시 알아야 하는 개념이 바로 포인터다. 또 다른 고급 언어(Python, Java 등)에는 없는, 메모리에 직접 접근할 수 있다는 것도 포인터가 지닌 장점 중 하나이다.

 

포인터로 할 수 있는 것

포인터 변수에는 변수가 저장된 메모리의 특정 장소, 즉 메모리 주소값을 저장할 수 있다. 포인터 변수에 변수의 메모리 주소값을 저장하고, 포인터 변수를 통해 해당 변수를 참조해서 값을 바꿀 수 있다. 또 필요한 경우 포인터에 원하는 만큼 메모리 공간을 할당하여 사용할 수 있다.

 

포인터 변수 선언하기

포인터도 하나의 변수이다. 다만 자료형으로 따로 존재하는 것이 아니라 int *pnt(자료형 * 포인터 변수명)으로 구성되어 있고, 이를 쉽게 풀어쓰자면 메모리 주소값을 저장할 int 자료형의 pnt라는 포인터 변수라고 할 수 있다. 또 변수 앞에 주소 연산자 &를 붙여 변수의 주소값을 포인터 변수에 할당할 수 있다.

#include <stdio.h>

int main() {
	int num1 = 10;
	int *pnt;
	pnt = &num1;
    
    printf("%d", *pnt); // ans: 10
	return 0;
}

 

포인터 자료형이 따로 존재하지 않는 이유?

그건 바로 포인터에 저장되는 메모리 주소값은 모두 정수형이지만, 선언하는 자료형에 따라 메모리에 접근하는 방법이 다르기 때문이다. 각각의 자료형의 크기에 맞게 동적으로 값을 저장하거나 가져올 수 있다면 메모리 할당 측면에서 보다 효율적이다.

 

참조 연산자 사용하기

변수 앞에 &를 붙이면 해당 변수의 메모리 주소를 알아낼 수 있다. 비슷한 방법으로 포인터 변수가 가지고 있는 메모리 주소를 통해 특정 변수의 값을 가져오고 싶다면 포인터 변수 앞에 참조 연산자 *를 붙여주면 된다. 다소 헷갈리는 개념이지만, 포인터 변수를 선언할 때 붙이는 *는 해당 변수가 포인터 변수라는 것을 일러주기 위함이고, 포인터에 사용할 때는 해당 포인터에 있는 메모리 주소를 통해 변수의 값을 참조하겠다는 의미이다.

#include <stdio.h>

int main() {
	int num1 = 10;
	int *pnt;
    pnt = &num1;
    
    printf("%p", &num1); // num1의 메모리 주소 출력
    printf("%d", *pnt); // pnt의 메모리 주소를 통해 num1 참조
    printf("%d", num); // 일반적인 출력
    
    (*pnt) += 20; // pnt의 메모리 주소를 통해 변수 값 변경
    
    printf("%d", *pnt); // ans: 30
    
    return 0;
}

 

Call by value

함수를 작성할 때 넘겨줄 인자를 변수의 값으로 할지, 변수의 메모리 주소값으로 할지는 해당 함수의 용도에 따라 달라진다. 그냥 변수의 값을 인자로 사용한다면 이는 함수를 선언함과 동시에 값만을 복사하기에 함수 내에서 쓰이고 변경될 수 있지만 원래 변수의 값에는 영향을 미치지 않는다. 이를 변수의 값만을 복사하여 연산을 실행하는 Call by value라 칭한다.

#include <stdio.h>

void swap(int a, int b) {
	int temp = a;
    a = b;
    b = temp;
}

int main() {
	int a = 10;
    int b = 30;
    
	printf("a= %d, b= %d", a, b); // a= 10, b= 30
    
    swap(a, b);
    
    printf("a= %d, b= %d", a, b); // a= 10, b= 30
    return 0;
}

 

Call by reference

그렇다면 메모리 주소값을 함수의 인자로 넘겨준다면 어떨까? 해당 함수를 실행하는 과정에서는 단순히 변수의 값이 아닌 메모리 주소를 통해 변수에 접근하기에 원래 변수의 값을 변경할 수 있다. 다만 C언어에서 해당 과정 또한 단순히 메모리 주소값을 복사하는 것이기 때문에 기술적으로는 Call by value(이 케이스에서는 Call by adress)라고 볼 수 있겠지만, 이 방식을 통해 결과적으로 Call by reference에 이를 수 있기에 편의상 Call by reference라고 설명하는 게 보편적이다.

#include <stdio.h>

/*
*a, *b의 의미: 해당 변수에 a의 메모리 주소값이 들어가면,
그 주소를 통해 a의 값을 가져온다.
*/
void swap(int *a, int *b) {
	int temp = *a;
    *a = *b;
    *b = temp;
}


int main() {
	int a, b;
    a = 10;
    b = 20;
    
    printf("a= %d, b= %d\n", a, b); // a= 10, b= 20
    
    swap(&a, &b); // a, b의 주소를 입력
    
    printf("a= %d, b= %d\n", a, b); // a= 20, b= 10
    return 0;
}
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함