프로그래밍/C언어

값에 의한 호출(call by value)과 참조에 의한 호출(call by reference)에 대한 이해 C언어

콘파냐 2014. 2. 11. 19:13

함수에서 외부의 값(실인수)을 전달받기 위해 사용되는 변수를  형식인수라한다. 이 형식인수에 외부값(실인수)이 전달되는 방식에 따라 값에 의한 호출과 참조에 의한 호출로 나뉘어 지는데, 값호출과 참조호출로 나뉜다. 일반적으로 실인수를 형식인수에 전달시 대입연산을 하는 경우와 마찬가지 동작이 일어나, 실인수의 값을 형식인수에 대입을 한다. 메모리상에선 실인수의 값을 복사한 후 형식인수에게 할당을 한다. 그 결과 같은 값을 지닌 변수가 서로 다른 메모리 공간에 2개 존재하게 된다. 이 경우 형식인수값을 조작하더라도 실인수의 값은 어떤 영향도 받지 않다. 이런 호출방식을 값호출이라고한다.


그럼 참조에 의한 호출은 어떤 것인까?

실인수의 값을 전달하는 것이 아닌 주소를 전달하는 것이다. 사실 내부적으로 보면 값호출이나 참조호출이나 같은 동작이 일어난다. 주소도 갓이므로 주소값이 형식인수에 복사가 된다. 그런데 주소값을 전달하기 위해서는 형식인수의 타입은 실인수타입의 포인터여야 한다. 즉 참조호출은 형식인수가 포인터기 때문에, 내부적으로는 실인수의 값을 알기위해서는 형식인수(포인터)에 의한 참조 방식으로 알아야 한다. 결국 이런 전달방식은 실인수에 직접 접근이 가능하다.



그럼 값호출과 참조호출의 차이점을 간단히 예를 들어보자


값에 의한 호출

위 코드의 동작후 결과 값은 3을 출력한다. 의도한바는 a의 값을 전달받아 3을 더 더해서 6이 되길 바라는 코드였다. 그런데 위에서 설명했듯이, 값에의한 호출은 값만을 형식인수에 복사하기 때문에, 실인수 a와는 아무런 상관없이 함수내부의 형식인수가 6의 값을 갖는다. 함수내부의 a라는 값은 지역변수기 때문에 함수가 리턴될 때 바로 소멸된다.


함수 내부에서 외부의 값을 다루기 위해선 포인터에의한 참조를 통해 외부값을 조작해야한다.


참조에 의한 호출

위 코드는 참조호출로 바꾼 코드다. 결과 값은 6을 출력한다.

단순히 주소값을 전달하여 내부적으로는 실인수에 접근하여 값을 조작했다. 함수내부에서 선언된 지역변수인 형식인수 a가 소멸되지만, 소멸과 관계없이 실인수 a의 값은 조작된 후다. 



그러면 이번엔 좀 더 깊게 생각해보자.


위 코드는 동적 메모리의 함수를 우해 래퍼함수인 n_call 함수를 만든 것이다. 포인터를 전달한후 동적할다을 하여 TEST라는 값을 넣었다. 그리고 실인수의 값을 출력하는 코드이다. 그런데 이상하게 제대로 동작하지 않는다.

분명 name도 포인터 변수고, name 가리키는 공간의 주소값을 넘겨주어서 그 공간에대한 메모리의 동적 할당을 하는 것인데 왜 안될까.. 이렇게 생각 될 수도 있겠다. 그러면 다음의 그림을 보자.


값에 의한 호출이 된 경우

좀 헷갈릴 수 있겠으나, 기본적인 동작은 같다. 실인수의 동적할당을 제대로 받기 위해선 실인수의 포인터를 전달해야한다. 위 그림은 형식인수가 동적할당은 받은 후 TEST를 입력받았다. 이 경우도 함수가 리턴된후 a의 값은소멸된다. 그리고 Name은 아무런 변화가 없다. 즉 값에의한 호출이다.

 단순히 Name의 값만 바꾸려 했다면 제대로 동작 했을 것이다. 이런일이 일어나는 이유는 함수내부에 있는 malloc이 포인터의 값을 변화시키는 함수기 때문이다. 때문에 포인터를 기준으로 생각해야한다.

실제로 원하는 동작을 만들기 위해선 형식인수로 &Name을 전달해야하며, 형식인수의 타입은 char **a 가되어야 한다. 그리고 함수 내부에서 형식인수는 '*'연산으로 실인수의 실제 값을 참조해야한다. 다음 그림을 참조하길바란다.


제대로 참조에 의한 호출이 된경우



2014/02/11 - [프로그래밍/C언어] - 이중포인터에 대한 이해 C언어


이경우 C언어의 문자열을 다루는 형식의 특성상 2중포인터를 사용하긴 했으나, 실제로, 다른 참조호출의 동작과 같은 것이다. 원리 또한 동일하다. 단지 위 경우는 기준점이 포인터 Name 이었기 때문이다.

반응형