06
10
728x90

C언어 계열의 코딩 공부를 하며 변수를 선언하고 사용함에 있어서 "변수의 주소값" 에 대한 개념이 등장하는데, 이는 매우 중요한 개념이지만 처음 접하면 헷갈릴 수 있는 개념이다.

 

주로 함수의 매개변수로 넘겨주거나 배열을 사용할 때 많이 사용하는 것이 주소값이다.

 

C++에서 포인터와 비슷한 것 같으면서도 다른 개념이 있다.

바로 이번에 다룰 참조자 개념이다.

 


포인터

먼저 간단하게 C언어의 포인터 부터 살펴보겠다.

#include <iostream>

using namespace std;

int main() {
    int a = 10;
    int *pa = &a;

    // 변수에 들어있는 값
    cout << "value >>\n";
    cout << "a: " << a << '\n';
    cout << "*pa: " << *pa << '\n';

    cout << '\n';

    // 변수의 주소값
    cout << "address >>\n";
    cout << "&a: " << &a << '\n';
    cout << "pa: " << pa << '\n';
    cout << "&pa: " << &pa << '\n';

    return 0;
}

 

먼저 변수 a를 선언하고 10을 담는다.

포인터 pa를 선언하고 변수 a의 주소값을 담는다.

 

a에 들어있는 값을 출력하면 당연히 10이고,

pa에 들어있는 값(a의 주소값)에 들어있는 값을 표현하기 위해 *pa를 출력하면 10이 나온다.

 

메모리상에 잡혀있는 a의 주소값을 확인하기 위해 &a를 출력하면 16진수로 된 주소값이 나오고

포인터 변수 pa에는 a의 주소값이 똑같이 들어있다.

하지만 포인터변수 pa자체의 주소값인 &pa의 주소값은 위의 주소값과 다르다.

 

참조자와 포인터 변수의 차이점을 알기 위해 주의깊게 봐야 할 것이 바로 포인터변수 자체의 주소값과 그 안에 들어있는 주소값이다.

 

즉, 포인터변수 pa는 변수a와 다른 메모리를 할당받고있고, 단지 pa가 a의 주소값을 담고있다는 점을 기억하면 된다.

 


참조자

다음으로 참조자의 예제를 보자.

#include <iostream>

using namespace std;

int main() {
    int a = 10;
    int &b = a;

	// 변수에 들어있는 값
    cout << "value >>\n";
    cout << "a: " << a << '\n';
    cout << "b: " << b << '\n';

    cout << '\n';

	// 변수의 주소값
    cout << "address >>\n";
    cout << "&a: " << &a << '\n';
    cout << "&b: " << &b << '\n';

    return 0;
}

먼저 C++에서의 참조자는 변수 이름 앞에 &를 붙이면 된다. 이후 참조자에 a를 담고 값을 출력하면 같은 10이 나온다.

 

이후 a와 참조자 b의 주소값을 출력 해 보면 같은 주소가 나온다.

 


포인터와 참조자의 차이점

결론적으로 C언어의 포인터와 C++의 참조자는 같은 Call By Reference형태로 사용할 수 있다

 

하지만 포인터는 원래의 변수와 다른 변수를 메모리에 할당받고 그 포인터변수가 원래의 변수를 가리키는 형태라면

참조자는 그 변수 자체가 이름만 달라졌다고 볼 수 있다.

 

그렇다면 참조자는 메모리를 아예 할당하지 않는가? 라고 할 수 있는데, 컴파일러에 따라 컴파일 시 메모리 공간이 필요하다면 할당하고 그렇지 않으면 할당하지 않는다.

 


참조자의 사용법

먼저 참조자의 선언이다.

int &b = 10;        // 상수로 초기화할 수 없다.

int &b;                // 초기화되지 않으면 안된다.

int &b = NULL;   // NULL로 초기화할 수 없다.

 

위의 세 가지만 지키면 된다.

 

참조자를 사용할 때 가장 흔하게 사용하는 방법으로 함수의 매개변수로 넘겨주는 것이다.

#include <iostream>

using namespace std;

// 그냥 매개변수
void calc1(int a) {
    a -= 3;
}

// 참조자 매개변수
void calc2(int &a) {
    a -= 3;
}

int main() {
    int a = 10;

    cout << a << '\n';
    calc1(a);   // Call By Value
    cout << a << '\n';
    calc2(a);   // Call By Reference
    cout << a << '\n';

    return 0;
}

간단히 살펴보면

먼저 main()에서 calc1()로 값만 넘겨준 경우이다.

calc1()안에서 아무리 a를 지지고 볶아도 main()에서의 a값은 변하지 않는다. 왜냐면 main()의 a와 calc1의 a는 이름만 같지 다른 변수이기 때문이다.(지역변수 개념)

 

하지만 calc2()의 매개변수를 보면 참조자로 되어있다.

즉, main()의 a와 calc2()의 a가 같은 변수를 참조한다고 보면 된다.

그렇기에 calc2()에서 a값을 3 빼니까 main()에서 a를 출력했을 때 7이 출력되는 것이다.

 

매개변수 형태로 참조자 사용 시 함수를 호출할 때 바로 초기화되는 것과 같은 형태가 되므로 위의 형태로 사용할 수 있는 것이다.

728x90

'개발 > C, C++' 카테고리의 다른 글

[C++] STL 1편 - STL이란?  (0) 2022.07.07
[C++] XOR 연산 이용 swap  (0) 2022.06.12
[C++] namespace란?  (0) 2022.06.10
[C++] 입력받기(cin, get, getline)  (0) 2022.04.18
[C++] 배열 최대값, 최소값 구하기  (0) 2022.04.18
COMMENT