"Call by Value, Call by Reference".
C언어를 배울때 한번쯤을 들어보았을 용어입니다.
다시한번 해당 내용을 정리해보도록 하겠습니다.
프로그래밍 언어에서 변수에 값을 적는다는 것은, 컴퓨터 시스템의 메모리에
데이터를 기록하는 행위와 동일하다고 보면 될것 같습니다.
그리고 메모리는 주소 체계로 구성되어 있으므로, 따라서 데이터를
제어하는 모든 작업은 내부적으로 메모리 주소를 사용해서 진행됩니다.
하지만 프로그래머는 직접 주소를 조작하지 않고 변수를 사용한 프로그래밍
방법이 개발및 유지보수에 있어 훨씬 용이합니다.
이전 어셈블러의 프로그램밍 방식에서 해방될 수 있기 때문입니다.
또한 C언어는 필요시 포인터(*)와 주소 지정연산자(&)을 사용해서
주소를 이용한 방식의 프로그램도 제작할 수가 있습니다.
1. Call by Value
아래 코드는 두 개의 변수룰 선언하고, 각 변수를 sum함수의 인자로 대입
한 후, 변수의 합을 넘겨주는 코드 입니다.
포인터(&)와 주소연산자(&)가 사용되어지지 않았습니다
#include <iostream>
#include <stdarg.h>
using namespace std;
int sum(int data1, int data2);
void main()
{
int a = 4;
int b = 3;
int total = sum(a , b);
cout << "SUM:" << total << endl;
}
int sum(int data1, int data2)
{
int sum = data1 + data2;
return sum;
}
메모리 측면에서 main함수안에 선언된 변수는 main함수의 스택영역안에
존재하고, sum함수가 수행될때 인자인 data1,data2 그리고 sum함수
안에서 선언한 sum변수는 sum함수 스택영역에 존재합니다.
즉, main함수와 sum함수의 각 변수들은 물리적으로 전혀 연관이
변수의 값만 sum함수 호출시 전달이 되며, sum함수에서 수행결과
값만 return문을 통해서 받게 되는 것입니다.
변수의 값을 통해서 함수 호출이 이루어지며, 서로 변수간의
직접적인 연관이 없는 것을 call by value라고 할 수 있습니다.
call by value형태에서 호출한쪽에서 값을 받기위해서는
호출된 함수에서 return XXX와 같이 반드시 값을 지정해야 합니다.
2. call by reference
call by reference는 주소에 의한 참조를 말하며,
call by value처럼 변수에 저장된 값을 전달하는 것이 아니라,
메모리상의 변수 주소 자체를 전달해서 처리하는 방식 입니다.
C언어에서는 포인터(*)와 주소연산자(&)을 통해 사용가능 합니다.
int a=3;
int* a_ptr = &a;
정수형 포인터 변수 a_ptr은 변수 a의 주소를 저장하게 됩니다.
코드를 통해 확인을 해보겠습니다.
void main()
{
int a = 4;
int* a_ptr = &a;
cout << "a변수의 주소:" << &a << endl;
cout << "a_ptr변수의 값:" << a_ptr << endl;
cout << "a_ptr변수의 값을 읽으면: " << *(a_ptr) << endl;
int b = 3;
int total = sum(a , b);
cout << "SUM:" << total << endl;
}
cout출력문을 다음과 같이 확인할 수 있습니다.
주소연산자 &을 통해서 a변수의 주소를 출력했고, 포인터변수 a_ptr의 저장된
값 역시 변수 a의 주소임을 확인할 수 있습니다.
출력하기 전에 int* a_ptr = &a를 통해서 해당 변수에 a변수 주소를 지정했기
때문입니다. 그리고 포인터 변수에 저장된 주소값을 읽어 올때는 다음과 같이
*(포인터변수)와 같이 사용합니다.
여기서 포인터변수에는 주소 값이 저장되어 있으므로 해당주소의 값을 읽어오면
결국 4가 되는 것입니다.
call by valus는 변수의 값을 조작하는 방식입니다. swap함수 안에서
바껴진 변수 값을 리턴 받아서, 원래의 변수에 값을 다시 넣어주면,
결국 call by value형태로 swap이 되는 것이죠.
이렇게 하기 위해서는 두 개의 리턴 값을 받아야 하는데 C언어에서는
다중 인자 리턴이 허용되지 않습니다.
따라서 구조체를 하나 만들어서 거기게 값을 넣어서 리턴하는 형태로
구성을 해보겠습니다.
#include <iostream>
#include <stdarg.h>
#include <string>
using namespace std;
typedef struct __change
{
int x;
int y;
}MyChange;
MyChange swap(int data1, int data2);
void main()
{
MyChange change_value = { 3,2 };
change_value = swap(change_value.x,change_value.y);
cout << "First value:" << change_value.x << endl;
cout << "Second value:" << change_value.y << endl;
}
MyChange swap(int data1, int data2)
{
MyChange change_value = { 0,0 };
int temp = data1;
data1 = data2;
data2 = temp;
change_value.x = data1;
change_value.y = data2;
return change_value;
}
Call by Reference(SWAP)
call by reference를 사용한 swap를 진행해 보겠습니다.
call by referene는 메모리 상의 변수의 주소를 가지고 제어하는
형태 입니다. call by value의 return 형태가 아니더라도 주소 값을
가지고 변수를 조작할 수가 있습니다.
#include <iostream>
#include <stdarg.h>
#include <string>
using namespace std;
void swap(int* data1, int* data2);
void main()
{
int a_value = 2;
int b_value = 3;
swap(&a_value, &b_value);
cout << "A value:" << a_value << endl;
cout << "A value:" << b_value << endl;
}
void swap(int* data1,int* data2)
{
int tmp = *data1;
*data1 = *data2;
*data2 = tmp;
}
Call by Reference(Sum함수)
이제 마지막으로 1번의 call by value형태의 sum함수를 call by reference 형태로 변경을 해보도록 하겠습니다.
즉, 별도의 return없이 주어진 값으로 변경을 한다는 내용인것이죠.
sum값을 저장하는 변수를 선언하고, 해당 변수의 주소를 다른 인자와 같이
전달하도록 하겠습니다.
#include <iostream>
#include <stdarg.h>
#include <string>
using namespace std;
void sum(int data1, int data2, int* total);
int main()
{
int a_value = 2;
int b_value = 3;
int sum_value = 0;
int* sum_ptr = &sum_value;
sum(a_value, b_value, sum_ptr);
//sum(a_value, b_value, &sum_value);
cout << "The sum value:" << sum_value << endl;
return 1;
}
void sum(int data1, int data2, int* total)
{
*total = data1 + data2;
}
return값을 받지 않고, 둘사이 연산을 저장할 변수의 주소를 인자로
전달해서 sum함수 내에서 더한결과를 바로 해당 변수에 저장하는
방법으로 sum함수를 구현 했습니다.
call by value, call by reference어떤 형태도 사용가능하며,
적절한 방법으로 사용하시면 될것 같습니다.