주소

0차

1차 

 &p

p

*p 

122EF560 

125F7458 

71 


Note ) java에서 말하는 참조 변수와, C++에서 말하는 참조 변수가 다름을 알아야 혼동을 피할 수 있다.

C++에서 참조 변수는 java나 C에는 없는, 변수 자체의 alias 개념이다 ( case 3 참조 )

java에서 참조 변수란 C나 C++에서 말하는 포인터 변수와 동일하다. 즉 배열, 객체 등을 가리키는 변수를 말한다.

( C의 포인터 변수와 다른 점은 참조 변수에 아무 값이나 대입할 수는 없다는 것이다. )

아마 java가 포인터를 지원하지 않으면서 포인터 변수 보다는 참조 변수라는 말을 쓰는 것 같다.


case 1: call-by-value

java는 항상 call-by-value다. ( 정확하게는 call-by-sharing = call-by-object 라고 한다. python도 마찬가지. )

배열이나 객체를 넘길 때 주소가 넘어가니 call-by-reference라고 착각하기 쉽지만 

"call-by-value where the value is reference" 라고 이해해야 한다.


참조 변수에 저장된 주소(p)가 넘어가게 되는데, 이는 type이 주소( reference )일 뿐 p라는 참조 변수에 저장된 value다. 

그리고 받는 측에서 이것을 받아 p와는 다른 새로운 곳에 할당된 p0에 저장한다.

즉 변수에 저장할 "값"을 받았으므로, call-by-reference가 아니라 call-by-value다. 


예제 코드는 차이를 알기 쉽게 모두 CPP pseudo-code로 작성했다.

```cpp

main(){

    int *p;

    swap(p);

}

swap(int *p0){

    *p0 = 0;

}

```


case 2: call-by-address

그렇다면 포인터에 저장된 주소(a)자체가 변하면 call-by-reference인가?

포인터에 저장된 주소(a)를 변경하려면 포인터 변수 자체의 주소(&a)를 넘겨야 하니 call-by-reference인 것 같지만 변수 자체의 주소를 넘긴다고 해서 항상 call-by-reference인 것은 아니다.

C를 사용하다 보면 아래와 같이 포인터를 사용해 외부 함수의 변수에 접근하는 경우가 많은데,

C는 call-by-reference를 지원하지 않는다. 다만 포인터를 사용하면 call-by-reference처럼 쓸 수 있다.

```cpp

main(){

    int a, b;

    swap(&a, b);

}

/*call-by-reference, b는 call-by-value라고 착각하기 쉽지만

 둘 다 call-by-value다.*/

swap(int *a0, int b0){

    int tmp;

    tmp = *a0;

    *a0 = b0;

    b0 = tmp;

//물론 b는 안바꿔진다만 예를 들기위해.

}

```

C에서는 이처럼 &a를 파라미터로 넘겨 a를 호출 func에서 수정할 수 있다. 

&a로 a의 주소를 넘기므로 실제로 main함수의 a값이 변경되지만, 그렇다고 해서 이게 call-by-reference는 아니다. 

a라는 변수 자체가 넘어간 것이 아니라 case1처럼 주소(&a)를 값으로 취급하고 이 값을 넘긴 것이며, a0이라는 변수에 담을 값을 받은 것이다. ( a0 = &a ) case1과 다른점은 변수 자체의 주소값이 넘어가긴 한다는 점이다.

변수 자체의 주소( &a )를 넘겨 함수에서 a를 수정할 수 있도록 하는 것. 이를 call-by-address라고 부르는 경우도 있다.

아무튼 swap이라는 함수 내에서 a의 값에 접근할 때는 * 연산자를 사용해서 포인터로 접근하는 수 밖에 없다.



call-by-reference는 다음과 같은 형식이다.

case 3: call-by-reference

```cpp
int main(){
    int a, b;
    swap(a, b);
}

swap(int &a1, int &b1){
    int tmp;
    tmp = a1;
    a1 = b1;
    b1 = tmp;
}
```


a라는 변수 자체가 넘어가는 call-by-reference라면 위와 같이 받는 쪽에서 argument를 &a로 정의할 수 있어야 한다.

a1이라는 변수에 담을 값을 전달 받은게 아니라, a1자체를 a를 사용하는 것과 마찬가지로 사용할 수 있다.(alias)

C++에서는 이렇게 참조 변수, reference variable을 통해 call-by-reference가 가능하지만, C나 java 등에서는 이를 제공하지 않는다.


reference의 정확한 의미는 다음과 같다.


A reference is an alias, or an alternate name to an existing variable


즉 case3의 a1, b1은 reference variable이며 a, b의 alias다.

그러나 case2의 a0는 type부터가 포인터인, 단순히 a를 가리키는 새로운 pointer variable이다.


call-by-reference라면 *없이 사용 가능해야한다.





참고


https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_reference


http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value/12429953#12429953


http://stackoverflow.com/questions/33622787/are-pointers-considered-a-method-of-calling-by-reference-in-c