티스토리 뷰

반응형

1) 목표

    ▶함수 파라메타 유형에 대해서 알아보기

  • call-by-value 이해하기.
  • call-by-reference 이해하기.

2) 설명

  • 함수에 넘겨주는 파라메타(인자값)의 유형은
    값을 넘겨 주는 방식(call-by-value),
    주소(포인터)를 넘겨 주는 방식(call-by-reference)이 있습니다.
  • call-by-value 방식은 함수를 부르는쪽이나 함수나 서로 영향을 주기 않습니다.
    14.함수에서 살펴본 sum(int a, int b) 함수가 call-by-value의 전형적인 함수입니다.
  • call-by-reference 방식은 주소를 넘겨 주고, 넘겨 받아서 처리하기에 값에 영향을 줍니다.

3-1) call-by-value 방식 예제 프로그램

    ▶ vi func3.c

#include <stdio.h>

// val1값과 val2값을 바꾸는 swap함수

// call-by-value 방식
void swap_value(int val1, int val2) {
    int tmp;

    printf("swap_value: swap전 val1[%d][%p] val2[%d][%p]\n", val1, &val1, val2, &val2);

    // tmp를 이용한 val1 <-> val2
    tmp = val1;
    val1 = val2;
    val2 = tmp;

    printf("swap_value: swap후 val1[%d][%p] val2[%d][%p]\n", val1, &val1, val2, &val2);
}

// swap함수
void main() {
    int val1, val2;

    val1 = 100;
    val2 = 200;

    printf("main: swap_value() 호출전 : val1[%d][%p] val2[%d][%p]\n", val1, &val1, val2, &val2);

    // call-by-value 방식
    swap_value(val1, val2);

    printf("main: swap_value() 호출후 : val1[%d][%p] val2[%d][%p]\n", val1, &val1, val2, &val2);
}

    ▶ 컴파일/실행

~/c-lecture (master ✘)✭ ᐅ gcc -o func3 func3.c
~/c-lecture (master ✘)✭ ᐅ ./func3
main: swap_value() 호출전 : val1[100][0x7ffc1fbbb670] val2[200][0x7ffc1fbbb674]
swap_value: swap전 val1[100][0x7ffc1fbbb64c] val2[200][0x7ffc1fbbb648]
swap_value: swap후 val1[200][0x7ffc1fbbb64c] val2[100][0x7ffc1fbbb648]
main: swap_value() 호출후 : val1[100][0x7ffc1fbbb670] val2[200][0x7ffc1fbbb674]
~/c-lecture (master ✘)✭ ᐅ

    ▶ 분석

  • swap함수내에서는 swap전, swap후의 값을 보면 val1값과 val2값이 바뀌어 있는걸 보실 수 있습니다.
    그런데 main()내에서는 swap() 호출전이나 호출후의 값을 보면 그대로 인걸 알수 있습니다.
    이렇듯 call-by-value방식은 호출하는쪽의 변수값을 바꾸질 못합니다.
    이유는 main()함수내에서 int val1, val2; 선언시 메모리가 할당이 되고 swap_value()함수를 호출을 하면
    swap_value()함수에서 파라메타에 대해서 새로운 메모리가 할당이 됩니다.
    그래서 swap_value()함수내에서 작업하는 곳은 새롭게 할당된 메모리가 되어서 main()함수에서 할당받은 
    메모리에 여향을 주지 못합니다.
printf("main: swap_value() 호출전 : val1[%d][%p] val2[%d][%p]\n", val1, &val1, val2, &val2);
  • 선언한 변수에 대해서 메모리 주소를 알아 보기 위해서 이전 강의에서 배운 %p를 사용했습니다.
    또한 %p 에 대한 값으로는 변수에 대한 주소를 사용하기 위해서 변수앞에 & 를 붙여서 사용합니다.
    위의 결과를 보시면 main()함수에서 val1주소, val2주소가 swap_value()함수에서는 전혀 다른 주소가 출력된걸 확인하실 수 있습니다.
  • main()에서 선언한 val1, val2값을 바꾸기 위해서는 어떻게 해야할까요?
    해답은 이전 강의에서 배운 포인터가 사용됩니다. 알아볼까요?

3-2) call-by-reference 방식 예제 프로그램

    ▶ vi func4.c

#include <stdio.h>

// val1값과 val2값을 바꾸는 swap함수

// call-by-reference 방식
void swap_reference(int *pVal1, int *pVal2) {
    int tmp;

    printf("swap_reference: swap전 val1[%d][%p] val2[%d][%p]\n", *pVal1, pVal1, *pVal2, pVal2);

    // tmp를 이용한 val1 <-> val2
    tmp = *pVal1;
    *pVal1 = *pVal2;
    *pVal2 = tmp;

    printf("swap_reference: swap후 val1[%d][%p] val2[%d][%p]\n", *pVal1, pVal1, *pVal2, pVal2);
}

// swap함수
void main() {
    int val1, val2;

    val1 = 100;
    val2 = 200;

    printf("main: swap_reference() 호출전 : val1[%d][%p] val2[%d][%p]\n", val1, &val1, val2, &val2);

    // call-by-reference 방식
    swap_reference(&val1, &val2);

    printf("main: swap_reference() 호출후 : val1[%d][%p] val2[%d][%p]\n", val1, &val1, val2, &val2);
}

    ▶ 컴파일/실행

~/c-lecture (master ✘)✭ ᐅ gcc -o func4 func4.c
~/c-lecture (master ✘)✭ ᐅ ./func4
main: swap_reference() 호출전 : val1[100][0x7ffced6b8ae0] val2[200][0x7ffced6b8ae4]
swap_reference: swap전 val1[100][0x7ffced6b8ae0] val2[200][0x7ffced6b8ae4]
swap_reference: swap후 val1[200][0x7ffced6b8ae0] val2[100][0x7ffced6b8ae4]
main: swap_reference() 호출후 : val1[200][0x7ffced6b8ae0] val2[100][0x7ffced6b8ae4]
~/c-lecture (master ✘)✭ ᐅ

    ▶ 분석

  • 실행한 결과를 보시면 main() 내 val1, val2값이 swap_reference() 호출후에 바뀌어 있는걸 확인하실 수 있습니다.
    또한 main()함수내 val1, val2주소가 swap_reference()함수내에서도 같은걸 보실 수 있습니다.
    이렇듯 같은 메모리 주소를 사용하므로 변수에 영향을 줄 수 있습니다.
...
    // call-by-reference 방식
    swap_reference(&val1, &val2);
  • 함수를 호출할때 변수에 대한 주소를 넘겨주기 위해서 변수명 앞에 & 를 붙여서 넘겨 주고 있습니다.
...
// call-by-reference 방식
void swap_reference(int *pVal1, int *pVal2) {
  • 호출된 함수에서도 파라메타가 주소, 즉 포인터이므로 포인터 형으로 정의가 되어 있습니다.

3-2) call-by-reference 배열 예제 프로그램

    ▶ vi func5.c

#include <stdio.h>

// 배열값 hello를 world로 바꾸는 함수

// call-by-reference 방식
void array_reference(char *pStr) {
    char new_str[] = "world";
    int i;

    printf("array_reference: swap전 [%s][%p]\n", pStr, pStr);

    for (i = 0; i < 6; i++) {
        // new_str:world로 대체
        *(pStr + i) = new_str[i];
    }

    printf("array_reference: swap후 [%s][%p]\n", pStr, pStr);
}

// swap함수
void main() {
    char str[] = "hello";

    printf("main: array_reference() 호출전 : str[%s][%p]\n", str, str);

    // call-by-reference 방식
    array_reference(str);

    printf("main: array_reference() 호출후 : str[%s][%p]\n", str, str);
}

    ▶ 컴파일/실행

~/c-lecture (master ✘)✭ ᐅ gcc -o func5 func5.c
~/c-lecture (master ✘)✭ ᐅ ./func5
main: array_reference() 호출전 : str[hello][0x7fff674cba82]
array_reference: swap전 [hello][0x7fff674cba82]
array_reference: swap후 [world][0x7fff674cba82]
main: array_reference() 호출후 : str[world][0x7fff674cba82]
~/c-lecture (master ✘)✭ ᐅ

    ▶ 분석

  • main()함수의 str='hello'를 array_reference()에서 'world'로 바꾸는 프로그램입니다.
  • 결과를 보시면 main() 에서 호출전은 'hello', 호출후에는 'world'로 바뀌어 있는걸 확인 하실 수 있습니다.
    물론 str의 주소와 array_reference()내에서의 주소도 동일합니다.
...
    // call-by-reference 방식
    array_reference(str);
  • 이전 강의에서도 설명한대로 배열은 배열 이름 자체가 주소가 됩니다. 그래서 array_reference 호출시 배열변수명 str이 그대로 사용되었습니다.
...
// call-by-reference 방식
void array_reference(char *pStr) {
  • 함수 파라메타에서도 포인터형으로 정의되어 있습니다.
  • call-by-reference 방식은 c프로그램에서 상당히 많이 사용하는 방식입니다.
    함수호출 방식과 호출된 함수의 파라메타 정의에 대해서 이해하시기 바랍니다.
반응형

'리눅스 C-언어 초급과정' 카테고리의 다른 글

16. 구조체(struct)  (0) 2022.11.21
15. 문자열(배열) 다루기  (0) 2022.11.17
14. 함수  (0) 2022.11.16
13. 포인터  (0) 2022.11.16
12. 문자열(string)  (1) 2022.11.16
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함