참조 변수(Reference Variable)는 별칭(alias), 즉 이미 존재하는 변수의 또 다른 이름입니다. 참조가 한 번 특정 변수로 초기화되면, 이후에는 원래 변수 이름이나 참조 이름 중 어느 것을 사용해도 동일한 변수에 접근할 수 있습니다.
참조 vs 포인터: 무엇이 다를까?
참조는 흔히 포인터와 혼동되지만, 두 개념 사이에는 다음과 같은 세 가지 핵심적인 차이점이 있습니다.
NULL 참조 불가: 참조에는 NULL 값이 존재할 수 없습니다. 참조는 항상 유효한 메모리 저장 공간에 연결되어 있다고 가정할 수 있어야 합니다.
참조 대상 변경 불가: 참조는 한 번 객체로 초기화되면 다른 객체를 참조하도록 바꿀 수 없습니다. 반면 포인터는 언제든지 다른 객체를 가리키도록 변경할 수 있습니다.
생성 시 초기화 필수: 참조는 생성되는 순간 반드시 초기화되어야 합니다. 반면 포인터는 선언 후 언제든지 초기화할 수 있습니다.
C++에서 참조 생성하는 방법
변수 이름을 메모리상의 변수 위치에 붙어 있는 라벨(label)이라고 생각해 보세요. 그렇다면 참조는 그 메모리 위치에 붙은 두 번째 라벨이라고 볼 수 있습니다. 따라서 원래 변수 이름을 통해서도, 참조를 통해서도 변수의 내용에 접근할 수 있습니다.
예를 들어, 다음과 같은 코드가 있다고 가정해 봅시다.
int i = 17;
i에 대한 참조 변수는 아래와 같이 선언할 수 있습니다.
int& r = i;
선언문에서 & 기호는 '참조(reference)'로 읽으면 됩니다. 즉, 위 선언은 "r은 i로 초기화된 정수형(int) 참조"라고 해석합니다. 마찬가지로 double 타입이라면 "s는 d로 초기화된 double형 참조"처럼 읽습니다.
예제 코드
#include <iostream>
using namespace std;
int main () {
// 일반 변수 선언
int i;
double d;
// 참조 변수 선언
int& r = i;
double& s = d;
i = 5;
cout << "Value of i : " << i << endl;
cout << "Value of i reference : " << r << endl;
d = 11.7;
cout << "Value of d : " << d << endl;
cout << "Value of d reference : " << s << endl;
return 0;
}
실행 결과
Value of i : 5 Value of i reference : 5 Value of d : 11.7 Value of d reference : 11.7
실행 결과에서 확인할 수 있듯이, 참조 변수 r과 s는 각각 원본 변수 i와 d와 완전히 동일한 값을 출력합니다. 이는 참조가 단순히 새로운 메모리 공간을 할당받는 것이 아니라, 기존 변수의 메모리 위치를 그대로 가리키는 또 다른 이름이기 때문입니다.