관리 메뉴

JIE0025

[C++] 참조자 (&) 본문

기타 학습/Language

[C++] 참조자 (&)

Kangjieun11 2022. 5. 10. 16:03
728x90



일단 변수란 무엇인가.
변수 : “할당된 메모리공간에 붙여진 이름”

우리는 변수의 이름을 통해 변수에 할당된 메모리 공간에 접근한다.


참조자(&)

참조자는 하나의 메모리 공간에 2개 이상의 이름을 부여하기 위해 생겨난 개념이다.


회사에서 홍길동이 있는데 외국계 회사라 고유 닉네임이 있고, 홍길동의 닉네임은 RED라고 가정해보자.
홍길동님 이거 오늘까지 마무리해주세요~
RED님 이거 오늘까지 마무리해주세요~
해도 고유 닉네임이기 때문에 의사소통엔 문제가 없다.


참조자의 선언

참조자로 사용하고 싶은 변수명 앞에 &기호를 붙혀주면된다.

int num = 5;
int &n1 = num;

 

참조자의 특징

- 참조자의 수에는 제한이 없다.
- 참조자의 참조자를 선언할 수도 있다.  >> int& n2 = n1;
- 참조자는 변수에 대해서만 선언이 가능하며, 선언과 동시에 변수를 참조해야한다.


참조자 사용

#include<iostream>
using namespace std;

int main(){
	int arr[3] = {1,2};
	int &r1 = arr[0];
	int &r2 = arr[1];
	
	cout << r1 << endl;
	cout << r2 << endl;
	return 0;
}


참조자 함수

call-by-reference 란 주소 값을 전달받아 함수 외부에 선언된 변수에 접근하는 형태의 함수 호출을 의미한다.

참조자의 개념을 배운 이시점에서
call-by-reference는 두가지로 구분될 수 있다.
- 주소값을 이용
- 참조자를 이용


참조자를 이용한 call by reference
- 참조자는 선언과 동시에 변수로 초기화 되어야 하지만.
- 함수에 매개변수로서 선언될땐, 함수 호출시 전달되는 인자로 초기화가 된다.
>> 매개변수 자체가 함수가 호출될 때 초기화가 진행되므로 참조자를 매개변수로 선언할 수 있다.

void swap(int &r1, int &r2){
	int tmp = r1;
	r1 = r2
	r2 = tmp;
}

참조자는 닉네임과 같으므로
주소값을 이용한 call-by-reference처럼 *같은 기호를 따로 붙혀서 접근하지 않는다.


위의 swap 함수를 호출할 때
swap(a,b); 이런식으로 변수를 인자로 전달하면 괜찮지만

상수값을 전달하는 아래 같은 경우는 컴파일에러가 뜬다. 이는 인자값이 상수라서 공간이 사라지기 때문이다.
swap(3,5);



아래는 포인터변수를 swap하되, 매개변수로 참조자를 사용한 예시이다.

int main(){
	int n1 = 3;
	int *p1 = &n1;
	int n2 = 5;
	int *p2 = &n2;

	swap(p1, p2);
}

void swapPtr( int * (&prf1) , int * (&prf2)){
	int * ptr = prf1;
	prf1 = prf2;
	prf2 = ptr;
}

 

 

반환형이 참조형(&) 인 경우? 

: 반환 값을 무엇으로 저장하느냐에 따라 결과가 차이가 있다. 

이렇게 얘기하면 이해가 잘 안되니 예시를 봐야한다. 

 

#include<iostream>

using namespace std;

int& test(int &ref){
	ref ++
    return ref
}

int main(){
	
    int one = 1;
    int &two = test(one);
    
    one ++;
    two ++;
    
    cout << one << endl;
    cout << two << endl;
    
	return 0;
}

 

위 코드를 해석해보자.

- one이라는 변수공간이 있는데 1이 할당되어 있다. 

- test 매개변수는 &ref이기 때문에 one의 별명으로써 ref를 사용할 수 있게 되었다. 

- ref++ 는 one의 값을 1 증가시킨다. (2) 

- return ref는 &two 로 반환되면서 one의 별명으로써 two가 생겼다. > 함수의 생명주기가 끝나면서 ref라는 별명은 사라진다. 

- one 의 값을 1 증가시키고 (3)

- 별명 two를 사용해서 one의 값을 1 증가시키면 (4)

- one을 출력하면 >> 4

- two를 출력하면 >> 4

 

 

 

 

이번엔 return 이후에 그냥 int two 로 할당되는 경우를 봐보자.

#include<iostream>

using namespace std;

int& test(int &ref){
	ref ++
    return ref
}

int main(){
	
    int one = 1;
    int two = test(one);
    
    one ++;
    two += 100;
    
    cout << one << endl;
    cout << two << endl;
    
	return 0;
}

이 경우엔 반환 이후에 two라는 새로운 변수가 생겼다. 

one과 two는 서로 다른 메모리공간에 존재한다는걸 먼저 알고 해석해보자.

 

- one엔 1이있다. 

- test(one)을 통해 one에는 ref라는 별명이 생기고

- res ++ 을 해서 one의 값은 2가된다. ref는 별명이기 때문에 여기에서 ref를 출력해도 2가 나온다.

 

- return ref를 했을 때 ref의 값은 2이고 이 값이 two로 할당된다. 그러나 two는 one과는 독립적이기 때문에 ref를 통해 갈 수 있는 값만 전달된다. 이후 ref는 함수의 종료로 소멸된다. 

- one에는 2, two에는 2가 있는 상황에서

one ++;

two += 100; 을 하게 되면

one (3)

two ( 102) 가 출력되는 것을 확인할 수 있다. 

 

 

반환값을 int & two 에 저장하느냐, int two 에 저장하느냐에 따라 결과는 달라진다. 

>> 첫번째 경우

int one =1;

int &ref = one;

int &two = ref;

 

>> 두번째 경우

int one =1;

int &ref = one;

int two = ref;

 

 

 

 

const 참조자

참조자를 통해 값을 변경하지 않을려면 앞에 const 키워드를 사용하면 된다. 

const int& num = n;

 

🚫 논리적 오류 🚫

아래 경우를 C++ 에서 돌리게 되면 오류가 난다.

const int num1;
int & ref = num1;
ref = 3;

상수화된 변수 num1은 어떤 경로를 통해서도 값이 변경되면 안되는데 참조자를 통해 바꾸려고 한다는 점...

 

이부분은 C++에서 허용하지 않기 떄문에 

참조자를 선언하고 싶다면 const참조자를 사용해야한다. 

const int num1;
const int & ref = num1;

 

 

 

const 참조자를 이용한 상수 참조가 가능하다 ?

원래 참조자엔 변수를 할당해야만한다. 

그러나 const 키워드를 이용한 참조자에는 상수 참조가 가능하다.

임시 변수라는 걸 만들어 이 공간에 상수를 저장하고 참조자가 이를 참조할 수 있다.

 

const int& ref= 1;

 

이건 왜 만들어졌을까? 

함수의 매개변수로 참조자가 있다고 해보자. 

굳이 바뀌지 않을 어떤 상수 값을 전달하는 경우엔 인자값을 전달해주기 위해 변수를 생성해야만 하면 공간낭비가 일어난다.

 

이럴때 매개변수에 const int &  를 사용하면 된다.

#include<iostream>
using namespace std;

int add(const int & num1, const int & num2){
	return num1 + num2
}

int main(){
	cout << add(3,4) << endl;
}