ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [c/c++] call-by-value와 call-by-reference
    Programming/C++ 2019. 1. 8. 19:42

    *열혈C 프로그래밍 강의를 듣고 정리한 내용입니다. 잘못된 정보나 오타가 있을시 피드백 부탁드립니다.*




    - 들어가기전


     함수에게 인자를 전달하는 형태는 여러가지가 있습니다.

     C에서는 call-by-value와 call-by-reference가 가장 많이 쓰이는 형태이며 

     함수의 인자로 전달되는 대상에 따라 함수의 호출 방식이 구분되어집니다.


     단순히 값을 인자로 전달하는 경우를 '값에 의한 호출' 즉, call-by-value라 하고

     메모리 접근에 사용되는 주소값을 인자로 전달하는 경우 '참조에 의한 호출' 즉, call-by-reference라 합니다.


     

     



    Call-by-value (값에 의한 호출) :

     변수(메모리 공간에 저장된 값)의 값을 복사하여 함수의 인자로 전달하는 방식

    #include <iostream> 
    using namespace std;
    
    void func(int b);
    
    int main()
    {
    	int a = 10;
    	cout << "원본 a의 값은 " << a << endl;
    	func(a);
    	return 0;
    }
    
    
    void func(int b)
    {
    	b += 10;
    	cout << "복사된 a의 값은 " << b; 
    	system("pause>null");
    }
    
    

     

    - 결과



    복사된 변수 a의 값이 func함수에 인자(int b)로 전달된 형태의 call-by-value 예제입니다.

    출력된 결과를 통해 알 수 있는 사실은 아래와 같습니다.


    1. main 함수(실 매개변수)의 실제값을 복사해서 전달한다.

    2. 형식 매개변수의(함수측)값을 변경한다해도 실 매개변수(함수 호출 측)의 값은 변경되지 않는다.

    다른 말로, 함수 속 인자의 값이 변경되어도 함수 외부의 값에 적용되지 않는다.

    3. 값을 넘겨주는 형태이기 때문에 고비용, 복사손실이 발생한다.




    여기서 끝내기엔 2%부족한거 같죠..?

    더 쉬운 이해를 돕기위해 swap 예제를 가져왔습니다.

    #include <iostream>
    using namespace std;
    
    void swap(int argA, int argB);
    
    int main()
    {
    	int a = 10;
    	int b = 20;
    	cout << "Before swapping" << endl;
    	cout << "a: " << a << endl;
    	cout << "b: " << b << endl;
    
    	swap(a,b);
    
    	cout << "\nAfter swapping" << endl;
    	cout << "a: " << a << endl;
    	cout << "b: " << b << endl;
    	return 0;
    }
    
    
    void swap(int argA, int argB)
    {
    	int temp;
    	temp = argA;
    	argA = argB;
    	argB = temp;
    
    	cout << "\n";
    	cout << "argA: " << argA << endl;
    	cout << "argB: " << argB << endl;
    
    	
    	
    } 
    


    - 결과




    아래는 예제를 요약한 그림입니다.






    위 swap 예제를 살펴보면 변수 a와 b의 값이 argA와 argB에 대입되어서 전달됐음을 확인할 수 있습니다.

    argA와 argB는 아래와 같은 값 교환을 통해 서로의 값이 뒤바뀐 상태이구요

    temp = argA;
    argA = argB;
    argB = temp;

    출력 결과는 어떨까요? argA와 argB의 값이 바뀌었으니 a와b의 값도 바뀌었을까요? 결론은 아닙니다.

    그 이유는 앞에서 이야기했듯이 복사된 값이 변경되어도 원본의 값은 변경되지않기 때문입니다. 

    위 swap예제는 call-by-value를 사용했지만 '잘못된 방식'으로 사용한 예로, swap프로그램이 원하는

    목적에 다다르지 못했습니다.


    그렇다면 어떻게 원본의 값을 변경할 수 있을까요? 

    키(key)는 원본에 직접 접근이 가능한 참조에 의한 호출 즉, call-by-reference 함수 호출 방식입니다.




    Call-by-reference (참조에 의한 호출) :

    주소값을 함수의 인자로 전달하는 방식


    call-by-reference는 바로 swap예제로 call-by-value와 비교해보겠습니다.

    // call-by-reference using pointers 
    #include <iostream>
    using namespace std;
    
    void swap(int* argA, int* argB);
    
    int main()
    {
    	int a = 10;
    	int b = 20;
    	cout << "Before swapping" << endl;
    	cout << "a: " << a << endl;
    	cout << "b: " << b << endl;
    
    	swap(&a,&b);
    
    	cout << "\nAfter swapping" << endl;
    	cout << "a: " << a << endl;
    	cout << "b: " << b << endl;
    	return 0;
    }
    
    
    void swap(int* argA, int* argB)
    {
    	int temp;
    	temp = *argA;
    	*argA = *argB;
    	*argB = temp;
    
    	cout << "\n";
    	cout << "argA: " << *argA << endl;
    	cout << "argB: " << *argB << endl;
    
    	
    	
    }


    - 결과




    아래는 예제를 요약한 그림입니다.





    call-by-value가 아닌 call-by-reference를 적용한 swap예제입니다.

    출력된 결과를 통해 알 수 있는 것은 아래와 같습니다.


    1. main 함수(실 매개변수)의 주소값을 swap함수(형식 매개변수)에 전달한다.

    2. 형식 매개변수에(함수측)값을 변경하면 실 매개변수(함수 호출 측)의 값도 같이 변경된다.

    다른말로, 포인터로 전달받은 인자는 원본의 값을 변경할 수 있다.

    3. 고비용, 복사손실 문제를 해결할 수 있다.



    포인터를 사용하고있기 때문에 헷갈리시는 분들은 포인터 요약을 참고하세요


    swap(&a,&b);

    &연산자로 변수 a와 b의 주소를 구해 swap함수의 인자로 전달합니다.


    void swap(int* argA, int* argB);

    변수 argA와 argB는 포인터로 선언되어 변수의 메모리 주소를 가리킵니다.


    int temp;
    temp = *argA;
    *argA = *argB;
    *argB = temp;

    swap 함수 내부에서는 *(역참조 연산자)를 사용하고 있습니다. *은 가리키는 공간으로 가는거라했죠

    따라서 *argA와 *argB는 포인터가 가리키는 공간에 직접 접근하여 a와 b의 값을 저장합니다.



    • 정리하면


    swap함수 내에서의 *argA = main함수의 a

    swap함수 내에서의 *argB = main함수의 b


    argA와 argB가 a와 b의 메모리 주소를 포함하므로

    *argA와 *argB에 수행되는 모든 작업은 main()함수의 값을 수정할 수 있다.


    Comment

Designed by black7375.