C++ 초급 - 5. 포인터와 참조 (Pointers and References) (3 - 참조 (& 연산자))
2025. 2. 12. 18:49ㆍ프로그래밍 언어/C++
📌 5.3 참조 (& 연산자)
참조(Reference)는 변수의 별칭(Alias) 역할을 하는 변수이다.
참조를 사용하면 기존 변수를 새로운 이름으로 다룰 수 있으며, 포인터와 유사하지만 한 번 초기화되면 다른 변수를 가리킬 수 없는 특징이 있다.
참조는 특히 함수 매개변수 전달(Call by Reference)에서 자주 사용되며, 복사 비용을 줄이고 원본 값을 직접 수정할 수 있도록 해준다.
📌 1. 참조 변수의 선언 및 초기화
🔹 (1) 참조 변수 선언 방식
참조 변수를 선언할 때는 & 연산자를 사용하며, 반드시 초기화해야 한다.
💡 기본 문법
데이터타입 &참조변수명 = 기존변수명;
💡 예제: 참조 변수 선언 및 초기화
#include <iostream>
int main() {
int num = 10;
int& ref = num; // num을 참조하는 ref 선언
std::cout << "num: " << num << std::endl;
std::cout << "ref: " << ref << std::endl;
ref = 20; // ref를 변경하면 num도 변경됨
std::cout << "num 변경 후: " << num << std::endl;
return 0;
}
🔹 출력 결과
num: 10
ref: 10
num 변경 후: 20
💡 설명
- int& ref = num; → ref는 num의 참조자(별칭).
- ref = 20; → ref를 변경하면 num도 변경됨.
- 참조는 기존 변수와 메모리 주소를 공유한다.
⚠ 주의
- 참조 변수는 반드시 선언 시 초기화해야 한다.
int& ref; // ❌ 오류 발생 (초기화되지 않음)
- 참조 변수는 다른 변수로 변경할 수 없다.
int a = 10, b = 20;
int& ref = a;
ref = b; // ✅ 변수 값만 변경됨 (참조 대상 변경 ❌)
📌 2. 포인터와 참조의 차이점
참조(Reference)와 포인터(Pointer)는 둘 다 메모리 주소를 활용하지만, 사용 방식이 다르다.
비교 항목 | 포인터 (*) | 참조 (&) |
메모리 주소 저장 | 변수의 주소 저장 가능 | 변수를 직접 가리킴 (별칭) |
초기화 여부 | 나중에 초기화 가능 | 선언 시 반드시 초기화 |
NULL 가능 여부 | nullptr 가능 | NULL 참조 불가 |
참조 변경 가능 여부 | 다른 변수의 주소 저장 가능 | 한 번 초기화되면 다른 변수로 변경 불가 |
역참조 방식 | *ptr 사용 | ref 자체가 변수처럼 동작 |
💡 포인터와 참조 비교 예제
#include <iostream>
int main() {
int num = 10;
int* ptr = # // 포인터
int& ref = num; // 참조
std::cout << "포인터: " << *ptr << ", 참조: " << ref << std::endl;
*ptr = 20; // 포인터로 값 변경
std::cout << "포인터로 변경 후 num: " << num << std::endl;
ref = 30; // 참조로 값 변경
std::cout << "참조로 변경 후 num: " << num << std::endl;
return 0;
}
🔹 출력 결과
포인터: 10, 참조: 10
포인터로 변경 후 num: 20
참조로 변경 후 num: 30
💡 설명
- 포인터(ptr)와 참조(ref) 모두 num을 가리킨다.
- *ptr = 20; → 포인터를 통해 값을 변경 가능.
- ref = 30; → 참조를 통해 값을 변경 가능.
📌 3. 함수 매개변수에서 참조의 활용 (Call by Reference)
함수에서 매개변수를 전달할 때 값을 복사하는 대신 참조를 사용하면, 원본 값을 직접 수정 가능하다.
이 방식은 복사 오버헤드(Copy Overhead)를 줄이고, 성능을 향상시킬 수 있다.
🔹 (1) 값 전달 (Call by Value)
- 매개변수를 복사하여 함수 내부에서 사용하므로, 원본 값은 변경되지 않음.
💡 예제: 값 전달
#include <iostream>
void modifyValue(int x) {
x = 100; // x의 값 변경 (원본에는 영향 없음)
}
int main() {
int num = 10;
modifyValue(num);
std::cout << "값 전달 후 num: " << num << std::endl; // 10 (변경 없음)
return 0;
}
🔹 출력 결과
값 전달 후 num: 10
💡 설명
- modifyValue(int x)는 num을 복사해서 사용하므로 원본 값은 변경되지 않음.
🔹 (2) 참조 전달 (Call by Reference)
- 참조를 사용하면 함수 내에서 원본 값을 직접 변경 가능.
- 복사 비용이 발생하지 않으므로 성능이 향상됨.
💡 예제: 참조 전달
#include <iostream>
void modifyValue(int& x) { // 참조 매개변수
x = 100; // 원본 값 변경
}
int main() {
int num = 10;
modifyValue(num);
std::cout << "참조 전달 후 num: " << num << std::endl; // 100 (변경됨)
return 0;
}
🔹 출력 결과
참조 전달 후 num: 100
💡 설명
- modifyValue(int& x)는 num을 참조하므로, 원본 값이 직접 변경됨.
🔹 (3) 참조를 사용한 const 매개변수
- 원본 데이터를 변경할 필요는 없지만, 복사 비용을 줄이고 싶을 때 const를 사용한다.
💡 예제: const 참조 사용
#include <iostream>
void printValue(const int& x) { // x는 변경 불가능
std::cout << "값: " << x << std::endl;
}
int main() {
int num = 10;
printValue(num);
return 0;
}
🔹 출력 결과
값: 10
💡 장점
- 함수의 인자로 대용량 데이터(객체, 구조체)를 전달할 때 복사 비용 절감.
- 원본 데이터의 변경을 방지하여 코드의 안정성을 향상.
📌 4. 정리
개념 | 설명 |
참조 (&) | 변수의 별칭(Alias) 역할을 하며, 한 번 초기화되면 변경 불가능 |
포인터와 차이점 | 포인터는 주소를 저장하며 변경 가능, 참조는 한 번 연결되면 고정 |
함수에서 활용 | 참조 전달(Call by Reference)로 복사 오버헤드 감소 |
const 참조 | 원본 데이터 변경을 방지하면서 복사 비용을 절감 |