All Articles

call by value와 call by reference

함수를 정의해 사용할 때 호출함수와 피호출함수 사이에서 자료를 전달하는 방식은 값에 의한 자료 전달(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, tupleimmutable 객체는 값이 복사되어 call by value 방식으로 넘겨지고,
  • list, dict, setmutable 객체call by reference 방식으로 넘겨진다.