Call by value & Call by reference

박진영·2023년 7월 23일
1

Call by (value, reference)

정의

  • Call by value는 값에 의한 호출, 값이 복사되어 전달됩니다.
    Call by reference 는 변수의 참조(주소값)가 전달됩니다.

  • C/C++에서는 기본형(Primitive)을 Call by value 방식으로 전달하고
    참조자(&),포인터를 사용하여 Call by reference 방식을 지원합니다.

  • 자바/자바스크립트 에서는 참조형인 경우 Call by reference 처럼 작동하지만,
    C++에서의 참조자와 같은 개념이 없기 때문에 C++ 에서 말하는 Call by reference를 사용할 수 없습니다.

  • 변수의 주소값이 아닌 데이터가 저장된 주소 자체를 복사해서 넘겨주기 때문에 Call by value 로 보는 것이 맞을 것 같습니다.
    ( 데이터의 주소값을 넘겨주기 때문에 call by address 라고도 합니다. )

  • 자세한 내용은 아래에서 설명하겠습니다.



Call by Value 예시

예시1

var num = 1;

var copy = num;

console.log(num, copy); //1 1
  • num에 1을 저장하고 copy에 num을 할당하였습니다.
  • 1의 값이 복사되어 copy는 1을 받게되고 메모리에서 새로운 공간에 할당됩니다.

예시2

function save(copy) {
    copy = copy + 1 ;
}

var num = 1;

save(num);

console.log(num); // num == 1
  • 아래 그림처럼 값이 복사되어 전달되어 num과 copy는 다른 공간에 위치합니다.
    그래서 num의 값은 변하지 않습니다.


[참고]

엄격하게 표현하면 변수와 같은 식별자는 메모리 주소를 기억하고 있기 때문에
변수에는 값이 전달되는 것이 아니라 메모리 주소가 전달된다라고 볼 수 있습니다.

이처럼 데이터 자체 값이 아닌 메모리 주소를 전달하고, 전달된 메모리 주소를 통해 메모리 공간에 접근하면 값을 참조할 수 있게 된다.
또한 해당 값은 서로 다른 메모리 공간에 저장되는 것이 Call by value의 특징입니다.
(파이썬의 경우는 한쪽의 변수에 재할당이 이루어진 경우 서로 다른 메모리에 저장)


자바와 자바스크립트는 왜 Call by value(address) 라고 하는 걸까

예시 1 ( JS )

var person = {
	name: 'Park' 
};

var copy = person;
copy.name = 'JINY';

console.log(person); // JINY
  • person 변수에 객체 데이터의 주소 0x00004322가 할당되어 있습니다.
  • copy에 person을 할당하면 0x00004322 가 할당됩니다.
  • 데이터가 저장된 주소 자체를 복사하여 copy 변수에 전달한 것입니다.
  • copy를 변경했는데 person도 같은 주소를 가지기에 person의 name 도 JINY로 변경되었습니다.
  • 이렇듯 주소를 전달해서 Call by reference 라고 봐도 될 것 같지만, 아래 2번째 예시에서 문제가 있습니다.

예시 2 ( JAVA )

public class Main {

    static class Person{
        public String name;
        public Person(String name){
            this.name = name;
        }
    }

    static void swap(Person p1 , Person p2){
        p1.name = "박"; // "박진영 -> 박" 으로 변경
        p2 = p1; // p2 는 Park 를 가지고 있다가 p1을 할당
    }

    public static void main(String[] args) {
        Person p1 = new Person("박진영");
        Person p2 = new Person("Park");
        System.out.println(p1.name);
        System.out.println(p2.name);
    }
}
  • 변수는 스택, 객체는 힙 메모리에 관리되지만 편의상 함께 표현을 하였습니다.
  • p1과 p2는 person1과 person2 변수의 주소가 아닌 person1, person2 의 값을 전달합니다.
    그런데 그 값은 데이터의 주소값을 저장하고 있습니다..
    p1을 예로들면 p1에 person1의 주소값 0x000042F1 을 전달하는게 아닌,
    person1이 가지고 있는 값 0x000043FF 를 복사해서 전달하는 것이다.
  • 그래서 p1의 name 을 변경하면 person1 의 name 도 변하겠지만,
    p1 자체를 다른 객체로 변경한다면 주소값이 복사되어 넘어오기 때문에
    p1과 person1은 다른 공간에 위치하게 된다.



Call by reference

  • C++ 에서는 참조자(&) 를 사용하여 call by refernect 를 지원합니다.
    참조자를 사용하면 변수의 참조를 넘기게 됩니다.
  • &p1 에 person1의 주소가 전달되고 p1은 person1의 주소를 이어받기 때문에
    p1과 person1은 같은 취급을 할 수있게 되고 p1 에 값을 할당하면
    자연스럽게 person1 도 변경이 될 수 밖에 없다

#include <iostream>

using namespace std;
class Person
{
    public:
        string name;
};  

void SwapName(Person &p1, Person &p2){
    Person tmp = p1; //PARK 저장
    p1 = p2; //person1 JINY 으로
    p2 = tmp; // person2 PARK 저장
    // Person tmp = p1;
    // p1 = p2;
    // p2 = tmp;
}
 
int main()
{
    Person person1;
    Person person2;
    
    person1.name = "PARK";
    person2.name = "JINY";
    SwapName(person1, person2);
    
	cout << "a : " << person1.name << endl; // JIN
	cout << "b : " << person2.name << endl; // PARK
}
  • p1은 0x000043FF가 아닌 person1의 주소값을 가지게 되고
    p1 = p2 식에서 0x000042F1 위치에 p2의 값 0x00005321 이 저장되게 되고
    결국 person1도 0x00005321을 가지게 되는 것입니다.
  • 여기에서도 변수는 스택, 객체는 힙 메모리에 관리되겠지만 편의상 함께 표현 하였습니다.



  • 잘못된 부분이 있을 경우 코멘트 남겨주시면 감사하겠습니다.

참고

profile
안녕하세요

0개의 댓글