함수의 인자 전달 방식

이예원
POCS
Published in
7 min readAug 30, 2019

함수를 호출할 때, 호출된 함수에 인자(argument)를 전달하는 방식에는 몇 가지가 있다.

그 중 call by value(값에 의한 호출 방식), call by address(주소에 의한 호출 방식), call by reference(참조에 의한 호출)에 대해 알아보자.

call by value(값에 의한 호출 방식)

call by value 방식은 함수를 호출한 쪽(caller)에서 호출된 함수(callee)로 인자를 전달할 때, 실인자의 값(actual-parameter, argument)을 복사하여 호출된 함수의 형식 매개변수(formal-parameter)로 전달한다. 복사된 값은 함수 내에서 지역적으로 사용되는 local value라는 특징을 가진다.

함수를 호출한 쪽(caller)에서 인자값을 복사 방식으로 넘겨 주었으므로, 호출된 함수(callee) 내에서 어떤 작업을 하더라도 호출한 쪽은 영향을 받지 않는다.

다음은 call by value 방식으로 구현한 swap() 함수이다. a와 b의 값이 잘 바뀌어 있을까?

코드를 실행해보면 swap() 함수를 호출한 후에도 a와 b의 값이 변하지 않았음을 확인할 수 있다.

[실행결과]

before swap() : a = 10, b = 20

after swap() : a = 10, b = 20

다음 그림을 살펴보자.

[참고] 스택 메모리 공간

-함수가 실행될 때 필요한 공간으로, 함수의 매개변수, 지역변수, return 값이 저장된다.

-함수가 호출될 때 할당되어 함수가 반환되거나 종료되면 반환되는 공간이다.

우선, main() 함수가 실행되면 스택 공간에 main() 함수의 스택 공간이 할당된다.

main() 함수에서 swap() 함수를 호출할 때, main()의 실인자 a와 b의 값(10과 20)을 복사하여 전달한다. swap() 함수가 호출되면 swap() 함수 스택 공간에 형식 매개변수 x와 y의 공간이 할당되고, 전달된 a, b의 값이 x, y에 복사된다.

swap() 함수 내에서 x와 y가 값을 교환하여도 함수가 종료되면 swap() 함수 스택 공간은 사라지게 된다.

따라서 main() 함수로 돌아와서 a와 b의 값을 출력하면 값이 교환되지 않고 ‘a = 10, b = 20’을 출력하는 것이다.

call by address(주소에 의한 호출 방식)

함수의 인자 전달 방식으로 call by value만을 지원하는 C언어에서 주소(&) 및 포인터(*) 연산자를 사용하여 call by reference의 효과를 얻는 방법이다. 따로 call by address(또는 call by pointer) 방식으로 분류하기도 한다.

주소에 의한 호출 방식은 함수를 호출하는 쪽(caller)에서 주소 연산자(&)를 사용하여 실인자의 주소값을 호출된 함수(callee)의 형식 매개변수로 전달한다. 호출된 함수에서는 역참조 연산자(*, dereference)를 사용하여 그 주소값을 실인자에 액세스한다.

[참고] 역참조 연산자(*, dereference)

- 포인터가 가리키는 메모리 주소의 내용(값)을 가져오는 연산자이다.

다음은 call by address 방식으로 swap() 함수를 구현한 코드이다. 이번에는 a와 b의 값이 제대로 교환되었을까?

코드를 실행해보면 swap() 함수가 제대로 수행되었음을 확인할 수 있다.

[실행결과]

before swap() : a = 10, b = 20

after swap() : a = 20, b = 10

main() 함수에서 swap() 함수를 호출할 때, main()의 실인자 a와 b의 주소값(&a, &b)을 전달한다.

swap() 함수가 호출되면 swap() 함수 스택 공간에 포인터 매개변수 x와 y(*x, *y)의 공간이 할당되고, a, b의 주소값이 x, y에 전달되어 a, b의 공간을 각각 가리킨다. swap() 함수 내에서 포인터 x, y가 가리키는 값이 교환되고, 결국 a와 b의 값이 교환된다.

즉, swap() 함수에 실인자의 주소값을 넘겨주어 해당 주소 안의 값을 변경하였기 때문에, swap() 함수가 종료되어 swap() 함수 스택 공간이 사라지더라도 main()의 a, b는 서로 교환된 채 남아있게 되는 것이다.

call by reference(참조에 의한 호출)

C언어와 달리 C++에서는 call by reference를 지원한다. 참조에 의한 호출은 호출된 함수(callee)의 매개변수를 참조 매개변수로 선언하여, 함수를 호출하는 쪽(caller)에서 실인자를 참조(reference)하여 실인자와 공간을 공유하도록 하는 방식이다.

[참고] 참조(reference) 변수

- 이미 선언된 변수의 다른 이름, 즉 별명이다. 참조자(&)를 사용하여 선언한다.

- 참조 변수를 선언하면, 이름만 생성되며 별도의 공간이 할당되지 않고 초기화로 지정된 원본 변수의 공간을 공유한다.

함수 호출 시, 값에 의한 호출(call by value)과 모양이 동일하기 때문에 헷갈릴 수 있지만, 참조 매개변수를 가진 함수에 대한 호출이 참조에 의한 호출이다.

call by reference를 지원하는 여러 언어들이 있지만 C++로 구현한 swap() 함수를 통해 알아보자.

[실행결과]

before swap() : a = 10, b = 20

after swap() : a = 20, b = 10

swap() 함수가 호출되면, 참조 매개변수 x, y(&x, &y)는 실인자 a, b를 참조하도록 초기화되며(‘int &x = a;’, ‘int &y = b;’) 함수 내에서는 보통 변수처럼 사용한다. 참조 매개변수 x, y는 참조 변수이므로 swap() 함수의 스택 공간에 별도의 변수 공간이 할당되지 않고 이름만 존재한다.

x, y는 원본 변수 a, b의 공간을 공유하기 때문에, swap() 함수가 실행되어 x, y 값이 교환된 후 swap() 함수 스택이 사라져도 main()의 a, b는 교환된 값으로 남아 있는 것이다.

참고자료

--

--