본문 바로가기

교육 노트/C++ 기초강의

[C++ 때려 잡기] C++ 기초강의 2-3 call by value / call by reference

2018/08/24 - [교육 노트/C++ 기초강의] - [C++ 때려 잡기] C++ 기초강의 2-1 함수의 선언과 정의

2018/08/25 - [교육 노트/C++ 기초강의] - [C++ 때려 잡기] C++ 기초강의 2-2 함수 오버로딩


지금까지의 내용들은 이해하기 어려운 내용들은 아니였으나

이번 강의는 조금 컴퓨터적 사고가 필요해서 어렵게 느껴질 수도 있다.


해당 내용을 가르치기 전에  swap을 배워보자


1. swap (스왑)

swap은 변수 2개의 내용을 바꿀때 자주 사용하는 용어이다.

두 변수 x = 10; y = 20;일 때
이 두 변수를 x = 20, y = 10 으로 바꾸는 (서로 교환하는) 방법은?


한번 해보자

int x = 10;

int y = 20;

x = y;

y = x;


처음 생각하면 이런식으로 생각하겠지만

이렇게 하면 3번째 라인에서 x가 20 이 되어버려

마지막 y = x; 는 결국 y = 20 이고 y의 값이 변경되지 않는다.

그러면 c++ 에서 변수두개를 스왑하기 위해서는 어떻게 할지 한번 생각해보아라.


swap문제를 해결하기 위한 방법이 임시의 변수를 하나더 만드는것이다.

int x = 10;

int y = 20;

int temp = x;

x = y;

y = temp


값이 변경되기 전의 x값을 저장하는 임시 변수를 만들고 y는 해당 변수로 초기화해주는것이다.

이렇게 되면 x와 y의 값을 서로 변경할수있다.

해당 방식이 가장 일반적인 swap 방식이며

이러한 방식때문에 컴퓨터공학과 유머중에 컴공과 학생 두명이 자리를 바꾸려면 의자가 3개 필요하다는 말이있다.


ps. 임시 변수를 사용하지 않고도 변경하는 방법이있으나 일반적인 레벨에서는 딱히 사용할일도 없고 이해하기 어려우므로 강의에서는 생략하겠다.


이제 swap 기능을 구현하였으니

해당 swap을 두고두고 쓰기위해서 swap함수를 구현해보자


void swap(int x, int y)
{
  int temp = x;
  x = y;
  y = temp;
  return;
}

다음과 같이 swap함수를 구현 하였다.

int main()
{
  int x = 10;
  int y = 20;
  swap(x, y);

  cout << "X는 " << x << endl;
  cout << "Y는 " << y << endl;
  
  return 0;
}

다음 코드의 실행결과는 어떻게 될까


swap을 수행하여 x는 20 y는 10이 나오기를 기대할것이다.

그러나 해당 코드의 수행결과는

x,y의 값이 바뀌지 않았다


ps. 만약 값이 바뀌어있다면 이미 존재하는 swap함수가 수행된것이다. swap이름을 바꾸어보자


분명 값을 swap하는 함수를 짰고 함수내에서 x,y의 값을 교환하였는데 왜 해당 결과는 바뀌지않았을까?

함수를 잘못짠것인지 확인하기위해 출력을 함수내에서 해보자.

#include <iostream>
using namespace std;

void swap(int x, int y)
{
  int temp = x;
  x = y;
  y = temp;

  cout << "함수내 X는 " << x << endl;
  cout << "함수내 Y는 " << y << endl;
  return ;
}


int main()
{
  int x = 10;
  int y = 20;
  swap(x, y);

  cout << "X는 " << x << endl;
  cout << "Y는 " << y << endl;

  return 0;
}


함수 내에서는 기가막히게 잘 변경되었다.


그런데 왜 main에서 x,y는 변경되지 않았을까?


해당이유는 함수에 x,y를 넘겨줄때 값을 복사하기 때문이다.

이게 무슨 소리냐고?


2. call by value ( pass by value )

위의 swap함수의 과정을 컴퓨터 메모리관점에서 확인해보자


처음 main 에서 x,y가 만들어지면 해당 변수를 저장하기위해서 메모리에 x,y변수가 만들어진다.


그리고 swap함수를 호출하면 매개변수를 메모리에 새로 할당하고 매개변수로 들어온 값으로 초기화한다. 


따라서 swap함수에서 swap되는 x,y 와  main 의 x,y는 서로 다른 변수이므로 함수내 x,y의 값은 변경되나 main의 x,y는 유지되는것이다.



이제 함수가 끝나면 해당 메모리에 잡힌 내용이 날라가게 된다.


함수에 넘겨진 변수는 그 값을 메모리의 다른 공간에 복사하여 사용하므로 함수 내에서 값을 변경해도 넘겨진 변수 자체의  값이 바뀌지 않는다


이렇게 C++ 에서는 함수에 매개변수값이 넘어가는 과정이 들어온 값을 복사하면서 이루어진다.

이러한 동작을 콜 바이 벨류 또는 패스 바이 벨류 라고 한다.



3. call by reference ( pass by reference )

그러면 이러한 c++ 의 함수 특성때문에 swap함수는 영원히 만들수 없을까?

똑똑한 C++ 개발자들은 이런한 문제를 해결하기위해 reference라는 개념을 도입하였다.

레퍼런스는 참조라는 뜻으로 일종의 별명을 의미한다.

c++에서는 레퍼런스 변수라는 개념이 존재하여 다른이름으로 같은 메모리공간의 값을 가지게 할수있다.

추후 배울 포인터에 밀려 잘 사용하지 않는 변수타입이지만


함수의 매개변수로는 자주 사용되는 타입으로

int& y

과 같이 & 기호를 변수 타입뒤에 붙여 사용하게 된다.

이런 타입을 함수 매개변수에 적용하여

void swap(int& x, int& y)
{
  int temp = x;
  x = y;
  y = temp;
  return ;
}

다음과 같이 매개변수에 &를 추가해주면 해당 매개변수는 레퍼런스 타입으로 작동하게 된다.

다른 부분은 아무것도 건들일 필요없이 저거만 추가해주면된다.


이렇게 했을때 메모리 과정을 살펴보자


main 함수에서 변수가 생성되는과정은 동일하다.


여기에 swap함수가 실행될때 x,y는 레퍼런스타입 이므로 swap함수에서 따로 만드는 변수는 temp변수뿐이다.

swap함수에서 x,y값이 바뀌면 실제 main에서 넘겨준 x,y의 값이 변경되게된다.

이렇게 해서 swap함수를 사용할수가 있게 되었다.

이러한 과정을 콜 바이 레퍼런스 혹은 패스 바이 레퍼런스라 부른다.

Call by reference
함수 파라미터 자료형에 참조기호& 가 붙어있으면
해당 파라미터는 넘겨준 변수 그대로를 이용한다.

해당 swap을 직접 짜보면서 이해해 보도록 하자.



ps. 참고로 실제 메모리에서 과정이 완전하게 저런식으로 동작하지는 않는다.



728x90