0. 시작하기
- 맥 운영체제(OSX)에서 작성하였습니다.
- IDE는 VScode를 사용하였습니다. ( 사용법 => https://youngq.tistory.com/category/IDE/VScode)
- 모든 코드는 https://github.com/yekyu94 에 업로드 됩니다.
1. 포인터 ( CPP/Pointer.cpp )
참조자에 대해서 설명하기 위해서는 역시 포인터를 먼저 말하고 가야한다고 생각해서 적게되었습니다.
C언어를 입문하는 사람이 가장 힘들어하는 부분이 '포인터'라고 합니다.
포인터는 변수의 메모리상 주소를 가리키는 녀석을 말합니다.
조금 더 디테일하게 보겠습니다.
#include <iostream>
using namespace std;
int main(void){
int a = 10;
int *pt1 = &a;
int **pt2 = &pt1;
cout << a << endl; // a의 값
cout << &a << endl; // a의 주소값
cout << "\n---------------\n" << endl;
cout << pt1 << endl; // pt1의 값
cout << *pt1 << endl; // pt1이 가리키는 값
cout << &pt1 << endl; // pt1의 주소값
cout << "\n---------------\n" << endl;
cout << pt2 << endl; // pt2의 값
cout << *pt2 << endl; // pt2가 가리키는 값
cout << &pt2 << endl; // pt2의 주소값
return 0;
}
위와같은 코드를 하나 작성해보았습니다. 그리고 실행해보면 아래와 같은 결과를 볼 수 있습니다.
이를 그림으로 표현하면 아래와 같습니다.
어려워 보이는 개념일 수 있습니다만, 간단하게 생각해봅시다.
1개의 포인터(*)는 변수의 주소를 직접 갖고 있다는 의미입니다.
2개의 포인터(*)(=더블포인터)는 변수의 주소를 갖고있는 포인터의 주소를 갖고있다는 것을 말합니다.
포인터의 갯수가 3개, 4개가 되도 마찬가지입니다.(물론 3,4개씩 쓸일이 있을까 싶기는 합니다.)
C언어 기준으로 본다면, 포인터는 아래와 같습니다.
- int *pt : 변수의 주소값을 저장할 'pt'라는 포인터를 만듭니다.
- int **ptt : 변수의 주소값을 갖고있는 포인터의 주소값을 가리킬 (더블)포인터를 만듭니다.
- print(*pt) : 포인터 pt가 가리키는 값을 출력합니다.
- print(&pt) : 포인터 pt의 주소값을 출력합니다.
위의 4개만 알고있다면 포인터를 쉽게 사용은 못해도, 포인터를 이용한 다양한 알고리즘, 자료구조들을 이해하는데는 충분합니다.
2. 참조자 ( CPP/Reference1.cpp ~ Reference3.cpp )
그럼 본론으로 돌아가서 C++의 참조자에 대해서 언급해보겠습니다.
위에서 보았듯이 C++에서도 C언어와 마찬가지로 포인터(*)를 사용할 수 있는 것을 볼 수 있었습니다. 하지만, 프로그래밍을 할 때, 포인터를 사용한다는 것은 익숙하지 않은 프로그래머에게는 상당히 부담스러울 수 있는 일입니다.(난이도 때문)
이러한 문제 때문이었는지 C++에서는 '참조자'라는 특별한 친구를 만들어 주었습니다.
참조자는 변수에 대한 별명을 만들어주는 것이라 볼 수 있습니다.
예제 코드 몇개를 살펴 보겠습니다.
#include <iostream> // CPP/Reference1.cpp
using namespace std;
int main(void){
int x = 10;
int &y = x; // int y = x 사용시 결과는 11, 11
x++;
y++;
cout << x << endl;
cout << y << endl;
return 0;
}
만약 [ int y = x ]라고 해주었다면, 결과는 11, 11이 출력되었을 것입니다.
왜냐하면 변수라는 것은 [ 데이터 ]를 저장하는 공간이기 때문입니다. 데이터, 즉 값이라는 것을 저장하는 변수는 특정한 숫자나 특정한 문자열을 저장할 뿐이지 다른 변수의 주소값등을 저장하지는 못합니다.
따라서 위의 코드에서 [ int &y = x ]라는 부분이 특별한 기능을 한다는 것을 알 수 있습니다.
변수 선언과정에서 변수명 앞에 '&' 를 붙일 경우, 이것은 변수가 아닌 '참조자'라는 것으로 선언되었다는 의미를 갖습니다.
참조자는 위에서 언급한것과 같이 '변수'에 대한 '별명'을 붙여준다는 것을 말합니다.
위의 예제를 조금 수정해서 아래와 같이 실행해 보았습니다.
#include <iostream> // CPP/Reference2.cpp
using namespace std;
int main(void){
int x = 10;
int &y = x;
int &z = y;
cout << &x << endl;
cout << &y << endl;
cout << &z << endl;
return 0;
}
위의 코드를 보게되면 '변수x'와 '참조자y'는 동일한 주소값을 갖고있는 것을 볼 수 있습니다.
그림으로 그려본다면 아래와 같은 모습임을 예측할 수 있습니다.
중요한것은 [변수x]와 [참조자 y, z]가 존재하는 형태라는 것입니다.
여러개의 변수가 하나의 데이터 공간을 공유하는 것은 아니라는 것을 꼭! 기억했으면 좋겠습니다.
( y 나 z가 없는 x는 존재할 수 있지만, x가 없는 y 또는 z 는 존재할 수 없습니다.)
참조자가 어떤 것인지는 대충 아셨을 것이라고 생각합니다. 그럼 이제 참조자가 어떤식으로 사용되는지 알아보겠습니다.
참조자의 가장 큰 특징은 딱 두가지입니다.
- 참조자는 선언과 함께 참조할 변수가 정해져야 합니다. ( int &x; 와 같이 선언 불가)
- 참조자는 함수 호출시 매개변수로 갖을 수 있다.
제가 설명력이 부족해서 이해하기 힘드실테니, 예제코드를 통해서 알아보겠습니다.
#include <iostream>
using namespace std;
void swap(int &a, int &b);
int main(void){
int x = 10;
int y = 20;
swap(x,y);
cout << x << endl;
cout << y << endl;
return 0;
}
void swap(int &a, int &b){
int temp = a;
a = b;
b = temp;
}
일반적으로 swap 함수를 사용할 경우 포인터를 사용해주었었습니다. 왜냐하면 함수의 경우 일반적으로 [Call-By-Value]를 원칙으로 하기 때문입니다.
( Call-By-Value, Call-By-Reference 에 대한 내용은 다음페이지에서 다루겠습니다. )
위의 swap 코드를 보게되면 [ int &a, int &b ]의 형태로 '참조자'를 이용한 것을 볼 수 있습니다.
따라서 이 swap 함수에서의 a, b라는 값은 메인함수의 [ x, y ]라는 변수의 '별명'이 되는 것을 볼 수 있습니다.
여기서 혹시 [ int &a ] 형태로 참조자는 선언할 수 없냐고 했는데 사용가능한건가? 하는 의문이 있을 수 있습니다.
결과는 당연히 가능합니다. 왜냐하면 함수의 매개변수는 함수가 코드내에서 실행되는 순간 할당되기 때문입니다.
위의 함수를 '인라인' 된것처럼 본다면 다음과 같은 코드가 될 것입니다.
#include <iostream>
using namespace std;
int main(void){
int x = 10;
int y = 20;
// Swap 함수 영역 시작
swap(int &a = x, int &b = y){
int temp = a;
a = b;
b = temp
}
// Swap 함수 영역 끝
cout << x << endl;
cout << y << endl;
return 0;
}
'실제 코드가 아닌 추상적인 코드입니다'
위와같이 함수는 실행되는 과정에서 각각의 매개변수에 값을 할당하기 때문에 참조자만을 선언하는 것이 아니라는 것을 알 수 있습니다.
참조자는 정말 중요한 개념이고 다양한 응용이 있기 때문에 다음 페이지에서 조금 더 알아보도록 하겠습니다.
'프로그래밍 > C++ - 이론' 카테고리의 다른 글
[C++ 정리] 9. 동적할당 (new & delete) (1/2) (0) | 2019.08.06 |
---|---|
[C++ 정리] 8. 참조자 (Reference) (2/2) (0) | 2019.08.06 |
[C++ 정리] 6. 메모리 구조 (Code, Data, Stack, Heap) (0) | 2019.08.05 |
[C++ 정리] 5. 네임스페이스 (NameSpace) (1) | 2019.08.05 |
[C++ 정리] 4. 인라인 함수 (Inline Function) (0) | 2019.08.04 |