C++ 포인터(2)

sjongyuuu·2021년 6월 30일
1

C++

목록 보기
2/6
post-thumbnail

C++포인터(1)에 이어서 설명하도록 하겠습니다.

무엇을 다루기로 했는지 다시 한 번 보자.

  • 배열을 동적할당 받는 경우
  • 포인터를 인자로 받는 함수를 정의하는 경우
  • 포인터를 반환하는 함수를 정의하는 경우

첫 번째 항목인 배열을 동적할당 받는 경우는 지난 포스팅에서 다루어 보았으니 이번 포스팅은 아래 2개의 항목에 대해 다루어 보려고 한다.

먼저, 포인터를 인자로 받는 함수를 보자.

void func(int* n) { ... }

위 코드의 경우 int형 포인터 변수를 인자로 받는 함수를 정의한 것이다.
이 경우, 함수를 정의할 때

  • 인자로 변수의 주소값을 n에 복사한다는 것과
  • 함수를 호출할 때 인자를 어떻게 넘겨주어야 하는지
    에 초점을 두어야 한다.

보다 더 구체적으로 이해해 보기 위해 다음 코드를 보자.

func(int *n) { ... } // 함수 정의

int y = 10;
int *x = &y; // 포인터 변수 정의

func(x); // 함수 호출 방법 1
func(&y); // 함수 호출 방법 2

함수 호출 방법 1은 포인터 변수 x를 함수의 인자로 넘겨주는 상황으로 x에 저장되어 있는 값 즉, 변수 y의 주소값을 포인터 변수 n에 복사하는 방식으로 함수를 호출한다.
함수 호출 방법 2는 변수 y의 주소값을 직접 함수의 인자로 넘겨주는 상황으로

int *n = &y;

위와 같이 호출이 진행된다.

다음은 위 코드에서 함수를 간단하게 정의하고 실행한 결과를 나타낸 그림이다.

출력 결과를 보면 함수 호출 방법 1함수 호출 방법 2 모두 n에 같은 주소값이 저장된다는 것을 알 수 있다.
또한, *n을 출력하면 n이 가리키는 실제값 10이 출력되는 것을 확인할 수 있다.
추가로, *n의 값을 변화시켜보면 main 함수에 선언된 y의 실제값 또한 변한다는 것을 확인할 수 있다.
.
.
.
다음으로, 포인터를 반환하는 함수에 대해 살펴 보자.

포인터를 반환한다는 것은

  • 주소값을 반환하는 것으로 이해하면 된다.

포인터를 반환하기 때문에 함수의 반환형이 포인터로 선언되어 있다는 것을 알 수 있을 것이다.

포인터를 반환하는 경우에는

  • 반환하는 주소값이 어떻게 정의되었는지
    초점을 두어야 한다.

바로 코드를 보자.

int *func(int x) { 
    int p = x + 1;
    return &p;
}

위의 경우, 변수 p의 주소값을 반환하는 형태로 정의되어 있다.
하지만, 이 경우 컴파일하면 다음과 같은 경고 메세지가 출력된다.

이는 변수 p가 함수 내부에서 선언된 "지역 변수"함수의 실행이 끝나면 변수 p가 메모리 상에서 소멸되기 때문에 나타나는 메세지이다.

이를 해결하기 위해선 다음과 같이 정의하여 주소값을 반환하도록 해야 한다.

코드를 보자.

  • 방법 1
int *func(int x) {
  int *p = new int; // 동적 할당
  *p = x + 1;
  return p;
}

방법 1의 경우,
함수 내부에서 동적 할당받은 주소를 반환하는 형태로 정의되어 있다.
동적 할당을 통해 p는 메모리 상에서 임의의 위치를 가리키고 있고 그 위치에 x+1의 값을 저장한다.
이후, 그 위치의 주소값을 반환하는데 함수를 실행해보면 결과를 알 수 있을 것이다.

  • 방법 2
int *func(int x) {
    int *p = &x;
    *p = x + 1;
    return p;
}

방법 2의 경우,
함수 내부에 선언된 지역 변수 x의 주소값을 반환하는 형태로 정의되어 있다.

여기서, 잠깐...
방법 2는 지역 변수의 주소값을 반환하는 형태로
func() 함수 내부에 선언된 지역 변수 x는 func() 함수의 실행이 끝나면 소멸된다.
이는 앞서 잘못된 예시로 설명한 경우와 같은 상황으로 볼 수 있다.

하지만, 함수를 컴파일하고 실행해보면 방법 1과 같이 정상적으로 결과가 출력되는 것을 확인할 수 있다.

포스팅을 하면서도 원인을 찾아보려 했지만 정확하게 파악하지 못했다. 하지만, 어느정도 예상이 되는 부분이 있어 이를 설명해 보려 한다.

  • 잘못된 예시
int *func(int x) { 
    int p = x + 1;
    return &p;
}
  • 방법 2
int *func(int x) {
    int *p = &x;
    *p = x + 1;
    return p;
}

잘못된 예시의 코드와 방법 2의 코드에서 차이점을 생각해보면 지역 변수의 주소값을 저장하는 것에 차이가 있다.

쉽게 말해 방법 2에서 지역 변수 x의 주소값을 포인터 변수 p에 저장한다.
따라서, 함수의 실행이 끝나 x가 소멸되어도 p는 그 위치를 가리키고 있다는 것이다.
하지만, x의 주소값은 저장한다고 해도 x의 값이 소멸되는 것은 설명이 불가능하다.

이 부분에 대해서는 이후에도 계속 고민해 보아야 할 것 같다.

C++ 포인터 [끝]

  • 읽어 주셔서 정말 감사드립니다.
  • 오타나 잘못된 정보를 댓글로 남겨주시면 정말 감사하겠습니다.
profile
개발 잘 하고 싶다

0개의 댓글