함수를 호출할 때 같이 넘겨주는 값을 매개 변수(parameter)라 한다. 매개 변수는 함수와 함께 스택 프레임(stack frame)에 저장되는데, 이 때 매개 변수를 스택 프레임에 저장하는 방법이 몇 가지 존재한다.
#include <stdio.h>
void inc(int);
int main(void) {
int num = 0;
printf("%d\n", num);
inc(num);
printf("%d\n", num);
return 0;
}
void inc(int value) {
value++;
return;
}
/*
결과
0
0
*/
대부분의 프로그래밍 언어에서 기본 옵션으로 채택하고 있는 방법으로, 원본 변수 num
의 값을 복사하여 스택 프레임에 저장하는 것이다. 따라서 함수 내부에서 아무리 매개변수 value
의 값을 수정해도 그것은 원본이 아닌 사본이기 때문에, 원본 변수 num
에는 아무런 영향을 미치지 못한다.
#include <stdio.h>
void inc(int*);
int main(void) {
int num = 0;
int* p_num = # // num을 가리키는 포인터 변수
printf("(main) num's value: %d\n", num);
printf("(main) num's address: %p\n", (void*) p_num);
inc(p_num);
printf("(main) num's value: %d\n", num);
return 0;
}
void inc(int* p_value) {
printf("(inc) p_value's value: %p\n", (void*) p_value);
printf("(inc) p_value's address: %p\n", &p_value);
(*p_value)++; // 매개변수 p_value가 가리키는 변수에 1만큼 더함
return;
}
/*
결과
(main) num's value: 0
(main) num's address: 0x7fffffffddfc
(inc) value's address: 0x7fffffffddfc
(inc) p_value's address: 0x7fffffffddd8
(main) num's value: 1
*/
C와 같이 참조자 개념이 없어 후술할 call by reference를 구현할 수 없는 언어에서 이를 모방할 수 있는 방법으로, 매개 변수로 원본 변수의 주소를 담은 변수, 즉 포인터 변수 p_num
을 call by value 형식으로 넘겨주어 그것을 통해 원본 변수를 다룰 수 있게 한다.
#include <iostream>
using namespace std;
void inc(int& ref_value) {
cout << "(inc) ref_value's value: " << ref_value << endl;
cout << "(inc) ref_value's address: " << &ref_value << endl;
ref_value++;
return;
}
int main(void) {
int num = 0;
int& ref = num; // num을 참조하는 참조자
cout << "(main) num's value: " << num << endl;
cout << "(main) num's address: " << &num << endl;
cout << "(main) ref's value: " << ref << endl;
cout << "(main) ref's address: " << &ref << endl;
inc(ref);
cout << "(main) num's value: " << num << endl;
return 0;
}
/* 결과
(main) num's value: 0
(main) num's address: 0x7ffcf7a7556c
(main) ref's value: 0
(main) ref's address: 0x7ffcf7a7556c
(inc) ref_value's value: 0
(inc) ref_value's address: 0x7ffcf7a7556c
(main) num's value: 1
*/
C++의 참조자를 사용하면 call by reference를 구현할 수 있다. 주솟값을 전달하여 함수 외부 변수에 접근한다는 점에서는 call by address와 비슷하지만, 참조자 변수 ref
의 주솟값이 num
의 주솟값과 같다는 것이 주요한 차이점이다. 이는 call by address와 같이 "주솟값을 담은 변수를 전달"한 것이 아닌 "주솟값 그 자체를 전달"한 것이 되고, call by reference의 정의와 상응한다.
def append_(list_l, value_v):
list_l.append(value_v)
return
a = []
print(a)
append_(a, 1)
print(a)
def inc(value):
value += 1
return
b = 1
print(b)
inc(b)
print(b)
'''
결과
[]
[1]
1
1
'''
결론부터 말하자면 파이썬에서는 매개 변수가 mutable하다면 call by reference로, immutable하다면 call by value로 전달된다. 이를 passed by assignment라 한다.