함수의 정의를 특정한 기능을 하는 일련의 로직이라 할 수 있는데 해당 기능을 수행하는데 필요한 인수가 필요할 것입니다. 이러한 인수 중에 호출하는 함수에서 초기 값을 전달하는 것을 입력매개변수로 내부에서 임시적으로 사용할 것은 지역변수를 통해 처리를 합니다. 또한, 해당 함수가 수행하고 난 후에 호출한 함수로 전달할 결과값을 리턴을 통해 전달해 줍니다.
int fnAdd(int first, int second)
{
int result =0;
result = first + second;
return result;
}
예를 들어 위와 같이 두개의 수를 더하는 함수가 있다고 한다면 기능을 수행하기 위해 두개의 수를 입력받아야 하고 두 수를 더한 결과값을 되돌려 주어야 할 것입니다. int fnAdd(int first, int second)에서 ()안에는 입력매개변수 리스트를 명시하게 되는데 충분히 많은(최대 31개) 입력 매개변수를 정할 수 있습니다. 또한 함수명 앞에 리턴 타입을 명시하게 되는데 리턴은 하나만을 전달할 수 있습니다.
int fnAdd(int first, int second) /* 함수 정의문*/ { int result =0; result = first + second; return result; } int fnAdd(int first, int second); /* 함수 선언문 */ int main() { int a = 3, b = 4; int c=0; c = fnAdd(a,b); /* 함수 호출문 */ printf("[%d] + [%d] = [%d]\n",a,b,c); return 0; } |
함수의 매개변수의 개념은 이와 같은데 실제 프로그래밍 언어마다 매개변수를 호출하는 곳에서 해당 함수로 전달하고 해당 함수에서 되돌려줄 값을 호출부로 전달하는 방법은 다릅니다. 특히 매개변수의 값을 전달하는지 변수 자체를 넘겨주는지는 해당 언어의 큰 특징이 됩니다. C언어에서는 매개변수의 값을 전달을 하고 있습니다.(call by value) 참고로 변수 자체를 넘겨주는 것을 참조에 의한 전달(call by reference)방식이라고 합니다.
0.1.2 매개변수 전달 방식(call by value vs call by reference)
값에 의한 전달(call by value)은 전달할 변수의 값을 복사하고 복사된 값을 전달하는 방식이며 참조에 의한 전달(call by reference)은 전달할 변수를 그대로 전달하는 방식입니다.
이를 좀 더 가슴에 와 닿게 하기 위해 두개의 입력 매개변수가 가지고 있는 값을 서로 바꾸는 swap이라는 함수를 통해 얘기를 하고자 합니다.(다른 많은 책에서도 이 예는 쉽게 볼 수 있을 것입니다.)
void fnSwap(int first, int second) /* 2 */ { int temp=0; /*3 */ temp = first; /* 4 */ first = second; /* 5 */ second = temp; /* 6 */ } int main() { int a=3, b = 4; /* 1 */ fnSwap(a,b); /* 2 */ printf("[%d] [%d]\n",a,b); /* 7 */ return 0; } |
먼저, C언어에서 전달하는 방식인 call by value일 경우에는 메모리 그림이 다음과 같이 진행이 됩니다.(int형이 4바이트로 가정하고 메모리 주소의 값은 설명을 위해 가정된 값입니다. 그리고, 예에 나와 있는 메모리 주소는 가상에 의한 것이며 할당된 순서도 가상에 의한 것일 뿐입니다.)
1 |
|
2 |
a,b의 값을 복사하여 전달되었다. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3 |
|
4 |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5 |
|
6 |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7 |
|
|
결론적으로 호출된 내부에서는 두개의 입력값이 바뀌어졌지만 호출한 부분으로 되돌아 왔을 때 원래 바꾸려고 했던 변수의 값은 바뀌지 않음을 알 수가 있습니다. |
만약, C언어가 매개변수를 call by reference에 의거해 전달한다라고 가정을 했을 경우에 메모리 그림은 다음과 같습니다. (가정에 의한 것입니다.)
1 |
|
2 |
a,b의 주소를 함수에 전달하고 본 함수에서는 first, second라는 변수명으로 할당된 메모리 주소를 관리한다. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3 |
|
4 |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5 |
|
6 |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7 |
|
|
|
그렇다면, C언어에서 swap시키려면 어떻게 해야 할까요? 이럴 때 포인터를 사용하면 쉽게 해결이 되겠지요. 즉, 호출하는 곳에서 바꾸려고 하는 두 개의 변수의 주소 값을 전달하여 피 호출 함수에서 해당 메모리 주소를 포인터 변수로 받아 간접 연산을 통해 처리하면 될 것입니다.
앞에서 연산자를 소개를 할 때 간접 연산자(*)과 주소 연산자(&)에 대해서 설명을 하였습니다. 혹시나 해서 간단히 이들에 대해 간단히 설명을 하고 넘어가도록 합시다. 간접 연산자(*)는 피 연산자로 포인터 타입이 와야 합니다. 해당 연산의 결과는 포인터가 갖고 있는 메모리 주소에 있는 값이 됩니다. 그리고 주소 연산자(&)는 피 연산자가 할당된 메모리 주소를 얻어오는 연산자라는 것은 잘 알고 있을 것입니다.(변수를 선언하면서 변수명 앞에 붙는 *연산자는 해당 변수가 포인터 변수라고 지시하는 연산자로 수행 코드상의 *인 간접연산자와는 다른 의미를 갖고 있습니다.)
|
위의 예는 간단히 간접 연산자와 주소 연산자를 설명하기 위한 예제 코드입니다. 코드의 1번은
다음은 C언어로 swap함수를 구현한 예입니다. 어떻게 주소 연산자와 간접 연산자를 사용하였고 메모리는 어떻게 변하고 있는지 확인해 보십시요.
void fnSwap(int *first, int *second) /* 2 */ { int temp=0; /*3 */ temp = *first; /* 4 */ *first = *second; /* 5 */ *second = temp; /* 6 */ } int main() { int a=3, b = 4; /* 1 */ fnSwap(&a,&b); /* 2 */ printf("[%d] [%d]\n",a,b); /* 7 */ return 0; } |
1 |
|
2 |
a,b의 메모리 주소를 &(주소 연산자)를 통해 얻어 해당 값을 복사하여 전달하였다. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3 |
|
4 |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5 |
|
6 |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7 |
|
|
|
'컴퓨터 > 언어,프로그래밍' 카테고리의 다른 글
[C언어] 포인터 - void *와 함수 포인터 (기본) (0) | 2009.03.23 |
---|---|
[C언어] 함수 - 함수 만들기 (0) | 2009.03.23 |
[C언어] 함수의 흐름 (0) | 2009.03.23 |
[C언어] 함수 - 정의 (0) | 2009.03.23 |
프로그래밍 단계 (0) | 2009.03.23 |