Channi Studies

[C++] 함수에서 포인터를 반환하기 (Returning a Pointer from a Function) 본문

C++/함수 (Function)

[C++] 함수에서 포인터를 반환하기 (Returning a Pointer from a Function)

Chan Lee 2023. 12. 22. 13:56

C++에서 함수는 포인터들도 리턴할 수 있습니다.

 

그러한 함수들은

type *funcion(); 

의 형태로 선언됩니다.

 

한가지 중요한 점은 '절대로 함수 내의 로컬 변수를 리턴하지 않는다.' 입니다.

 

간단한 예시 코드를 살펴보겠습니다.

int *largest_int(int *int_ptr1, int *int_ptr2){
    if (*int_ptr1 > *int_ptr2)
        return int_ptr1;
    else
    	return int_ptr2;
}

두개의 정수 포인터를 비교하여 더 큰 값의 정수의 포인터를 반환합니다.

이 함수를 사용하는 메인 함수의 예시는 다음과 같을 수 있습니다.

 

int main() {
    int a {30};
    int b {40};
    
    int *largest_ptr{nullptr};
    largest_ptr = largest_int(&a, &b);
    cout << *largest_ptr << endl;	// 40
    
    // or 
    
    int a{30};
    int b{50};

    int *largest_ptr = {largest_int(&a, &b)};
    cout << *largest_ptr << endl;	// 50
    
    return 0;
}

중요한 점은 &를 활용하여 pass by reference를 한 것과,
함수 내에서 비교한 것은 포인터의 값이 아닌, 포인터 값의 값이라는 점 입니다.

 

 

배열에 대한 함수로 한 가지 더 코드를 보여드리겠습니다.

int *create_arr(size_t size, int init_val=0){
    int *new_arr = new int[size];	// 배열 생성
    for (size_t i{0}; i < size; i++){
    	*(new_arr + i) = init_val;		// 초기화
    }
    return new_arr;			// 리턴
}

int main() {
    int *my_arr {create_arr(10, 50)}; // 길이 10의 50으로 초기화된 배열에 대한 포인터
    
    //배열 출력
    for (size_t i{0}; i < 10; i++){
    	cout << *(create_arr + i) << endl;
    }
    
    delete [] my_arr;
    
    return 0;
}

정수가 배열로 변경됬고, 

리턴 값이 생성된 배열에 대한 주소입니다.

 

여기서 헷갈릴 수 있는 점은 '로컬 변수의 포인터는 반환하지 말라고 한 것 아닌가?' 입니다.

 

이 규칙의 이유는 로컬 변수의 데이터는 heap 영역이 아닌 stack memory에 생성되기 때문입니다.

그리고 이 영역은 함수의 호출로 생성되고 리턴으로 사라집니다.

 

하지만 힙 영역에 존재하는 데이터는 한번 생성되면 사라지지 않습니다.

즉, 함수 호출 이후에 함수 종료 이후에도 계속 접근할 수 있는 값인 것 입니다.

 

위의 함수에서 보면, create_arr 함수 내에서

*new_arr 포인터가 선언되고 리턴되었습니다.

 

이 포인터가 가리키는 배열은 함수 영역에서 생겨나지 않고 힙 영역에서 생겼기 때문에, 

이를 반환해도 문제가 없는 것 입니다.

왜 힙 영역에서 생긴건지는 동적 메모리 할당에 관련된 포스트를 읽으면 이해하실 수 있습니다.

 

 

그렇다면 잘못된 예시들은 어떤것일까요?

int *wrong_func(){
    int size {};
    ...
    return &size;
}

int *wrong_func2(){
    int size{};
    int *size_ptr {&size};
    ...
    return size_ptr;
}

 

함수 내에서 선언된 변수 size에 대해서 

그 값 자체 혹은 그 값에 대한 포인터를 반환하는 것은 잘못되었습니다.

 

왜냐면 그 값이 스택 영역에서 생성되었다가 

함수 호출 종료 이후에는 사라질 값이기 때문입니다.

 

이런 문제는 당장 가시적인 오류를 발생시키지 않을 수도 있지만, 

언젠가는 치명적인 오류를 발생시킬 수 밖에 없습니다.

 

 

이러한 개념들을 합친 예시 코드입니다.

#include <iostream>

using namespace std;

int *create_arrary(size_t size, int init_val = 0) {
  int *new_storage = new int[size];

  for (size_t i{0}; i < size; i++) {
    new_storage[i] = init_val;
  }
  return new_storage;
}

void display_array(const int *const array, size_t size) {
  for (size_t i{}; i < size; i++) {
    cout << array[i] << " ";
  }
}

int main() {
  int *my_array = create_arrary(5, 100);
  display_array(my_array, 5);

  delete[] my_array;

  cout << endl;
  return 0;
}