라는 물음에 사실 돌려줄 값이 필요 없을 때라는 개념이 잘 와닿지 않았습니다. 왜 기껏 코드를 짰는데 값이 필요 없지? 하는 의문이 들었습니다.
그러니 예시와 함꼐 정리해보겠습니다.
예시
“문을 닫아 주세요”
→ 어떤 값을 가져올 필요 없이 행동만 하면 된다.
이때 두 번째처럼 함수가 어떤 작업만 수행하고, 호출한 쪽에 값을 돌려줄 필요가 없을 때 void를 사용
void는 함수의 반환 타입 자리에 쓰이며, 의미는
“이 함수는 실행은 하지만, 결과값을 반환하지 않습니다.”
이기에 출력하기, 상태 바꾸기, 저장하기, 초기화하기처럼 행동 자체가 목적인 함수에서 자주 사용된다.
반대로 계산 결과를 다른 곳에서 다시 써야 한다면 void보다는 int, float, bool 같은 반환 타입이 필요하다.
예시
변수 x를 “집”이라고 할 때,
포인터는 그 집의 주소를 적은 종이입니다.
주소 종이를 바꿔서 다른 집을 가리킬 수도 있고, 비어 있는 주소일 수도 있습니다.
참조자는 그 집에 붙인 별명으로,
한 번 별명을 붙이면 계속 같은 집을 부르고, “아무 집도 아닌 별명”은 만들 수 없습니다.

정리하자면, 포인터는 더 유연하지만, 잘못된 주소나 nullptr 때문에 좀 더 유의해야 하고,
참조자는 더 단순하고 안전하게 원본을 다룰 수 있지만, 한 번 연결한 대상을 바꿀 수 없습니다.
즉,
포인터 = 바꿀 수 있는 주소표
참조자 = 한 변수에 붙인 고정 별명
으로 기억하는 게 좋습니다.
포인터를 쓰는 대표적인 상황은 다음과 같습니다.
1. 가리키는 대상이 바뀔 수 있을 때
참조자는 한 번 연결하면 다른 변수를 가리킬 수 없는 반면, 포인터는 필요에 따라 A를 가리켰다가 B를 가리키는 식으로 변경할 수 있기 때문입니다.
2. 아무것도 가리키지 않는 상태가 필요할 때
포인터는 nullptr을 가질 수 있으므로
“아직 대상이 없다”, “찾는 객체가 없다” 같은 상태를 표현할 수 있습니다.
참조자는 반드시 어떤 변수와 연결되어야 해서 이런 표현이 어렵습니다.
3. 동적 메모리를 다룰 때
실행 중에 필요한 만큼 메모리를 만들고 관리할 때 포인터가 사용됩니다.
다만 C++에서는 직접 new/delete를 쓰면 실수 위험이 있다고 합니다.
4. 배열이나 큰 데이터의 시작 위치를 다룰 때
배열처럼 연속된 데이터는 시작 주소를 기준으로 접근할 수 있습니다.
이때 포인터는 “첫 번째 칸의 주소”를 들고 이동하면서 데이터를 다룰 수 있습니다.
간단히 정리하면
포인터는 이런 경우에 씁니다.
대상이 바뀔 수 있어야 할 때
대상이 없다는 상태가 필요할 때
메모리 주소를 직접 다뤄야 할 때
배열이나 동적 메모리처럼 주소 기반 접근이 필요할 때
반대로 단순히 함수 안에서 원본 값을 바꾸거나, 복사를 피하고 싶을 뿐이라면 참조자가 더 안전하고 읽기 쉬운 경우가 많습니다.
1. 원본 값을 바꾸기 위해
함수에 값을 그냥 넘기면 복사본이 전달되므로 함수 안에서 바꿔도 원본은 안 바뀔 수 있습니다.
하지만 레퍼런스로 넘기면 원본 자체를 다루는 효과가 있어서, 함수 안에서 변경한 내용이 원본에도 반영됩니다.
2. 큰 데이터 복사를 피하기 위해
큰 객체나 배열 같은 데이터를 매번 복사하면 비용이 큽니다.
레퍼런스를 사용하면 데이터를 통째로 복사하지 않고 원본에 바로 접근할 수 있어서 효율적입니다.
3. 포인터보다 문법을 단순하게 쓰기 위해
포인터는 주소, 역참조, nullptr 같은 개념을 신경 써야 하지만
레퍼런스는 일반 변수처럼 사용할 수 있어서 코드가 더 읽기 쉬운 경우가 많습니다.
4. 읽기 전용으로 안전하게 전달하기 위해
값을 바꾸면 안 되지만 복사는 피하고 싶을 때는 상수 레퍼런스를 사용합니다.
이러면 원본을 복사하지 않고 읽을 수는 있지만, 레퍼런스를 통해 수정할 수는 없습니다.
즉, 복사하지 않고, 원본을 안전하고 편하게 다루기 위한 별명입니다.