본문 바로가기

컴퓨터/언어,프로그래밍

[C언어] 함수 - 매개변수 전달하기

1.2       함수의 매개변수

함수의 정의를 특정한 기능을 하는 일련의 로직이라 할 수 있는데 해당 기능을 수행하는데 필요한 인수가 필요할 것입니다.  이러한 인수 중에 호출하는 함수에서 초기 값을 전달하는 것을 입력매개변수로 내부에서 임시적으로 사용할 것은 지역변수를 통해 처리를 합니다.  또한, 해당 함수가 수행하고 난 후에 호출한 함수로 전달할 결과값을 리턴을 통해 전달해 줍니다.

 

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

변수명

메모리주소

a

0x1000

3

b

0x1004

4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2

변수명

메모리주소

a

0x1000

3

b

0x1004

4

 

 

 

first

0x1010

3

second

0x1014

4

temp

0x1018

?

 

 

 

 

 

 

 

 

 

 

a,b의 값을 복사하여 전달되었다.

3

변수명

메모리주소

a

0x1000

3

b

0x1004

4

 

 

 

first

0x1010

3

second

0x1014

4

temp

0x1018

0

 

 

 

 

 

 

 

 

 

4

변수명

메모리주소

a

0x1000

3

b

0x1004

4

 

 

 

first

0x1010

3

second

0x1014

4

temp

0x1018

3

 

 

 

 

 

 

 

 

 

5

변수명

메모리주소

a

0x1000

3

b

0x1004

4

 

 

 

first

0x1010

4

second

0x1014

4

temp

0x1018

3

 

 

 

 

 

 

 

 

 

6

변수명

메모리주소

a

0x1000

3

b

0x1004

4

 

 

 

first

0x1010

4

second

0x1014

3

temp

0x1018

3

 

 

 

 

 

 

 

 

 

7

변수명

메모리주소

a

0x1000

3

b

0x1004

4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

결론적으로 호출된 내부에서는 두개의 입력값이 바뀌어졌지만 호출한 부분으로 되돌아 왔을 때 원래 바꾸려고 했던 변수의 값은 바뀌지 않음을 알 수가 있습니다.

 

 만약, C언어가 매개변수를 call by reference에 의거해 전달한다라고 가정을 했을 경우에 메모리 그림은 다음과 같습니다. (가정에 의한 것입니다.)

 

1

변수명

메모리주소

a

0x1000

3

b

0x1004

4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2

변수명

메모리주소

first(a)

0x1000

3

second(b)

0x1004

4

 

 

 

temp

0x1010

?

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

a,b의 주소를 함수에 전달하고 본 함수에서는 first, second라는 변수명으로 할당된 메모리 주소를 관리한다.

3

변수명

메모리주소

first(a)

0x1000

3

second(b)

0x1004

4

 

 

 

temp

0x1010

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4

변수명

메모리주소

first(a)

0x1000

3

second(b)

0x1004

4

 

 

 

temp

0x1010

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

5

변수명

메모리주소

first(a)

0x1000

4

second(b)

0x1004

4

 

 

 

temp

0x1010

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

6

변수명

메모리주소

first(a)

0x1000

4

second(b)

0x1004

3

 

 

 

temp

0x1010

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

7

변수명

메모리주소

a

0x1000

3

b

0x1004

4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 그렇다면, C언어에서 swap시키려면 어떻게 해야 할까요?  이럴 때 포인터를 사용하면 쉽게 해결이 되겠지요.  , 호출하는 곳에서 바꾸려고 하는 두 개의 변수의 주소 값을 전달하여 피 호출 함수에서 해당 메모리 주소를 포인터 변수로 받아 간접 연산을 통해 처리하면 될 것입니다.

 

  앞에서 연산자를 소개를 할 때 간접 연산자(*)과 주소 연산자(&)에 대해서 설명을 하였습니다.  혹시나 해서 간단히 이들에 대해 간단히 설명을 하고 넘어가도록 합시다.  간접 연산자(*)는 피 연산자로 포인터 타입이 와야 합니다.  해당 연산의 결과는 포인터가 갖고 있는 메모리 주소에 있는 값이 됩니다.  그리고 주소 연산자(&)는 피 연산자가 할당된 메모리 주소를 얻어오는 연산자라는 것은 잘 알고 있을 것입니다.(변수를 선언하면서 변수명 앞에 붙는 *연산자는 해당 변수가 포인터 변수라고 지시하는 연산자로 수행 코드상의 *인 간접연산자와는 다른 의미를 갖고 있습니다.)

 

void fnExam()

{

    int a=3, b=0, *p; /* 1 */

   

    p =  &a;        /* 2 */

    b = *p;          /* 3 */

}

1

변수명

메모리주소

a

0x1000

3

b

0x1004

0

p

0x1008

?

 

 

 

 

 

 

 

 

 

2

변수명

메모리주소

a

0x1000

3

b

0x1004

0

p

0x1008

0x1000

 

 

 

 

 

 

 

 

 

3

변수명

메모리주소

a

0x1000

3

b

0x1004

3

p

0x1008

0x1000

 

 

 

 

 

 

 

 

 

 

위의 예는 간단히 간접 연산자와 주소 연산자를 설명하기 위한 예제 코드입니다.  코드의 1번은 정수형 변수 2개와 정수형 포인터 변수 1개를 선언하였고 메모리 주소는 가정에 의한 값입니다.(정수형 변수가 2바이트인 컴파일러라고 가정)  코드 2번에서 a변수의 주소를 계산하기 위해서 &(주소 연산자)를 사용하였고 이를 포인터형 변수 p에 대입을 하였습니다.  이로 인해 p변수의 값이 a변수가 할당된 메모리 주소를 갖게 되겠지요.  코드 3번에서는 간접 연산자(*)를 이용하여 포인터 변수 p가 가지고 있는 값인 메모리 주소에 저장된 값을 변수 b에 대입하는 코드입니다.  여기서 우리는 2번에서 주소 연산을 통해 얻어온 메모리 주소를 저장하기 위해서는 포인터 변수가 필요하다는 것을 느낄 수 있습니다.  또한 3번에서 포인터 변수가 가지고 있는 것은 프로그램 상의 논리적인 메모리 주소이고 해당 메모리 주소에 있는 값을 얻거나 변경하고자 한다면 포인터 변수에 간접연산을 통해 접근할 수 있다는 것을 알 수 있습니다.  이처럼 프로그램 상에 포인터 변수나 배열, 주소 연산자가 사용이 되는 부분에 대한 이해나 사용은 머리 속에 있는 논리로 이해하는 것은 쉬운 것이 아니지만 메모리 그림을 가상으로 그려나가는 습관을 갖는다면 자신이 것으로 만드는 데 비용이 적게 들 수 있을 것입니다.

 

 다음은 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;

}

 

 정수형 변수는 4바이트이고 포인터 변수의 크기도 4바이트라고 가정을 하였을 경우에 메모리 그림을 단계별로 나타내어 보았습니다. 

 

1

변수명

메모리주소

a

0x1000

4

b

0x1004

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2

변수명

메모리주소

a

0x1000

4

b

0x1004

3

 

 

 

first

0x1010

0x1000

second

0x1014

0x1004

temp

0x1018

?

 

 

 

 

 

 

 

 

 

 

a,b의 메모리 주소를 &(주소 연산자)를 통해 얻어 해당 값을 복사하여 전달하였다.

3

변수명

메모리주소

a

0x1000

4

b

0x1004

3

 

 

 

first

0x1010

0x1000

second

0x1014

0x1004

temp

0x1018

0

 

 

 

 

 

 

 

 

 

4

변수명

메모리주소

a

0x1000

4

b

0x1004

3

 

 

 

first

0x1010

0x1000

second

0x1014

0x1004

temp

0x1018

3

 

 

 

 

 

 

 

 

 

5

변수명

메모리주소

a

0x1000

4

b

0x1004

4

 

 

 

first

0x1010

0x1000

second

0x1014

0x1004

temp

0x1018

3

 

 

 

 

 

 

 

 

 

6

변수명

메모리주소

a

0x1000

4

b

0x1004

3

 

 

 

first

0x1010

0x1000

second

0x1014

0x1004

temp

0x1018

3

 

 

 

 

 

 

 

 

 

7

변수명

메모리주소

a

0x1000

4

b

0x1004

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


제주삼다수, 2L,... 오뚜기 진라면 매운... 상하목장 유기농 흰... 남양 프렌치카페 카... 고려인삼유통 홍삼 ... 종근당건강 오메가3... 요이치 카링 유무선...