함수를 정의해 사용할 때 호출함수와 피호출함수 사이에서 자료를 전달하는 방식은 값에 의한 자료 전달(call by value)과 참조에 의한 자료 전달(call by reference) 방식으로 나뉜다.
값에 의한 자료 전달(call by value)
C 언어에서 기본적인 자료 전달 방식이다. 실매개변수와 형식매개변수 사이에서 값 자체가 전달되는 방식이다.
fcn1(10, 20); // 함수 호출(실매개변수)
int fcn1(int x, int y); // 함수 정의(형식매개변수)
선언한 함수 fcn1을 실행(fcn1(10, 20)
)하면 10과 20이라는 값이 형식매개변수로 그대로 복사된다. 따라서 피호출함수의 형식매개변수 값이 바뀌더라도 호출함수의 실매개변수 값에는 영향을 미치지 않는다.
#include <stdio.h>
void swap(int x, int y);
void main() {
int a = 3, b = 5;
printf("호출 전 a = %d, b = %d \n", a, b);
swap(a, b);
printf("호출 후 a = %d, b = %d \n", a, b);
}
void swap(int x, int y) {
int temp;
temp = x;
x = y;
y = temp;
printf("함수 내 x = %d, y = %d \n", x, y);
}
호출 전 a = 3, b = 5
함수 내 x = 5, y = 3
호출 후 a = 3, b = 5
함수 내부에서는 값이 바뀌었지만 호출 전과 후 a, b 값은 3, 5로 변화가 없다.
참조에 의한 자료 전달 방법(call by reference)
호출함수와 피호출함수간 실매개변수 값이 들어있는 주소값을 전달하므로, 전달 후 바뀐 형식매개변수 값을 되돌려받을 수 있다. 실매개변수와 형식매개변수 모두 같은 기억 장소를 가리키고 있으므로 형식매개변수 값이 바뀐 후 호출함수로 되돌아갔을 때 실매개변수 값은 바뀐 형식매개변수 값을 갖게 된다.
참조에 의한 자료 전달 방식에서는 실매개변수 앞에 주소를 나타내는 연산자 &를 붙여야 한다. 또한 형식매개변수는 *를 붙여 주소를 참조하는 포인터 변수로 선언해야 한다.
#include <stdio.h>
void swap(int *x, int *y); // 주소를 받을 수 있는 포인터 변수로 선언
void main() {
int a = 3, b = 5;
printf("호출 전 a = %d, b = %d \n", a, b);
swap(&a, &b); // 주소값 전달을 위해 주소 연산자 붙임
printf("호출 후 a = %d, b = %d \n", a, b);
}
void wap(int *x, int *y) {
int temp;
temp = *x;
*x = *y;
*y = temp;
printf("함수 내 x = %d, y = %d \n", x, y);
}
호출 전 a = 3, b = 5
함수 내 x = 5, y = 3
호출 후 a = 5, b = 3
형식매개변수 값이 변했더니 실매개변수 값도 따라서 변했다.
참고) 파이썬은 어떤 방식일까?
파이썬은 call by assignment 방식이다. 인자로 넘겨지는 객체 종류에 따라서 call by reference 방식, call by value 방식이 갈린다.
- int, float, str, tuple 등 immutable 객체는 값이 복사되어 call by value 방식으로 넘겨지고,
- list, dict, set 등 mutable 객체는 call by reference 방식으로 넘겨진다.