C++에서 참조자 다루기 … 포인터 전달 방법보다 편리

2015.10.27 13:59:13

[무료 등록] 최신 AI MCU 개발 트렌드와 함께 실제 산업 현장에서의 응용 방법을 소개합니다 (5/14, 코트야드 판교호텔 8층)

1. C++에서 참조자(Reference)의 개념

C, C++은 가장 많이 쓰는 언어 중 하나이다. C, C++에서 매개변수를 전달하는 방법에는 값에 의한 호출(call by value, pass by value)과 참조에 의한 호출(call by reference, pass by reference)이 있다. 


여기서는 참조자를 이용하여 매개변수를 전달하는 방법을 파악해 본다. 참조자는 변수에 별도의 명칭(별명)을 부여하는 것을 말한다. 왜 참조자를 쓰는가? 프로그램이 하나의 함수로 되어있다면 각 기억공간마다 하나의 이름이면 충분하다. 그러나 하나의 기억공간을 두 개의 함수에서 공유한다면 함수별로 개별적인 이름을 사용하는 것이 처리속도도 빠르고 편리하기 때문이다.

 

 

 

2. 참조자 형식

 

형명칭 &참조자 = 변수;
(예제) int &Hanla = mountain;

 

여기서 변수는 상수도 가능하며, 자료형은 서로 동일해야 한다. 만일 자료형이 서로 다르면 참조자의 주소가 변수의 주소와 다르게 설정되므로 프로그램이 비정상적으로 동작할 수 있다. 참조자가 선언되면 변수, 참조자 2개를 다 사용할 수 있다.

 

 

3. 참조자 예제

 

(예제 1)
#include <iostream>
using namespace std;

class Man
{
public:
 char irum[10]; 
 int nai;
};

void normal(Man x)
{
 cout << "x(normal)의 주소 :" << &x <<endl;
}

void special(Man& x) // 참조자
{
 cout << "x(special)의 주소 :" << &x <<endl;
}

int main()
{
 Man lsl;
 cout << "lsl의 주소 :" << &lsl << endl;
 normal(lsl);
 special(lsl);
 return 0;
}

 

 
<그림 1> (예제 1)의 실행 결과


위의 (예제 1)에서 변수 lsl과 참조자 x(special)의 주소가 동일한 결과를 나타낸다. 반면에 x(normal)의 주소는 다르다. 이것은 참조자가 변수 lsl과 이름이 다를 뿐 같다는 것을 의미한다.


참조에 의한 호출(call by reference, pass by reference)에는 참조자(&) 전달 방법과 포인터(*) 전달 방법이 있다. 두 방법을 비교하기 위해 다음과 같이 간단한 (예제 2)와 (예제 3)을 살펴본다. 참조자 전달 방법의 경우에는 참조자 인자를 사용할 때 선언 시에만 참조자로 선언해 주면 되고, 사용 시에는 일반 변수와 똑같은 방법으로 사용한다. 그런데 포인너 전달 방법에서는 포인터 인자는 항상 인자가 포인터 인자임을 감안하여 실인자에 &를 붙여줘야 한다.


(참고) 매개변수와 인자
인자(actual argument)는 함수를 이용한 데이터 전달 시 호출하는 곳(function call)에서 사용하며 실제 데이터를 말한다. 호출 함수의 함수명 다음의 소괄호 안에 표기한다. 그런데 매개변수(formal parameter)는 함수 내부에서 지역변수로 동작하며 호출하는 곳과 호출된 함수(called function) 사이에서 정보를 전달하는 매개체 역할을 한다. 그리고 함수 정의 부분에서 함수명 다음의 소괄호에서 정의한다. 매개변수는 함수를 호출할 때 인자값으로 초기화되므로 일반 변수와 다르다.

 

(예제 2)는 참조자(&) 전달 방식에 관한 것이다.

 

(예제 2)
#include <iostream>
using namespace std;

void exchan(int &x, int &y) // 참조자 사용
{
 int imsi;
 
 imsi = x;
 x = y;
 y = imsi;
}

int main()
{
 int x=5, y=10;
 cout << "exchan 호출 전, x : " << x << "  y : " << y<< endl;
 exchan(x, y);
 cout << "exchan 호출 후, x : " << x << "  y : " << y<< endl;
 return 0;
}

 

 
<그림 2> (예제 2)의 실행 결과


 

(예제 3)은 포인터(*) 전달 방식에 관한 것이다.

 

(예제 3)
#include <iostream>
using namespace std;

void exchan(int *x, int *y) //포인터 변수 사용
{
 int imsi;
 
 imsi = *x;
 *x = *y;
 *y = imsi;
}

int main()
{
 int x=5, y=10;
 cout << "exchan 호출 전, x : " << x << "  y : " << y<< endl;
 exchan(&x, &y);  //호출할 때 주소연산자 사용
 cout << "exchan 호출 후, x : " << x << "  y : " << y<< endl;
 return 0;
}

 

 

<그림 3> (예제 3)의 실행 결과

 


다음은 참조자(&) 전달 방식을 사용하여 class를 정의하고 국가 이름, 수도, 인구를 출력하는 프로그램이다.

 

(예제 4)
#include <iostream>
using namespace std;

class Nara
{
public :
 char name[20];   // 공개 멤버 변수
 char soodo[20];  // 공개 멤버 변수
 int ingoo;         // 공개 멤버 변수
};

void Showdata(const Nara &s) // 전달되는 인자를 참조자로 받고 있음.
{
 cout << " *** 국가 정보 *** " << endl;
 cout << " 국가 이름 : " << s.name << endl;
 cout << " 수도  : " << s.soodo << endl;
 cout << " 인구  : " << s.ingoo << endl;
}

int main(void)
{
 Nara country;  

 cout << " 국가 이름 : ";
 cin >> country.name;

 cout << " 수도  : " ;
 cin >> country.soodo;

 cout << " 인구  : ";
 cin >> country.ingoo;

 Showdata(country);

 return 0;
}

 

 
<그림 4> (예제 4)의 실행 결과

 


4. 분석과 고찰

(예제 2)와 (예제 3)에서 결과는 같게 나온다. 왜냐하면 참조자 전달방법이나 포인터 전달방법이나 방법이 다를 뿐 데이터를 교환하는 방식은 같기 때문이다. 그런데 포인터 전달 방법은 인자를 전달 시 명칭 앞에 항상 &를 사용해야 하므로 좀 불편하다. 그리고 포인터 전달 방법은 참조 시 Null이 될 수도 있으므로 반드시 0인지 확인해야 하는 반면 참조자 전달 방법은 한 번 생성한 후에는 다시 할당할 수 없으므로 Null 검사가 필요 없다. 그리고 참조자는 대응 변수와 다른 명칭의 동일한 형의 동일한 변수이므로 대응 변수와 동일한 방식으로 사용할 수 있다. 따라서 참조자 전달 방법이 편리하므로 실제 coding에서는 참조자 전달 방법을 많이 사용한다. 


(예제 4)에서는 void Showdata(const Nara &s)로 참조자 전달 방법을 구현하였는데 reference 앞에 const를 두어서 데이터의 조작을 허용하지 않도록 하였다. 또한 일반적인 참조자 전달 방법과는 약간 다르게 ‘키워드 class명 &(참조자 변수)’로 선언하였다.

  

윤덕하 객원전문기자

 

Copyright ⓒ 첨단 & Hellot.net




상호명(명칭) : (주)첨단 | 등록번호 : 서울,자00420 | 등록일자 : 2013년05월15일 | 제호 :헬로티(helloT) | 발행인 : 이종춘 | 편집인 : 김진희 | 본점 : 서울시 마포구 양화로 127, 3층, 지점 : 경기도 파주시 심학산로 10, 3층 | 발행일자 : 2012년 4월1일 | 청소년보호책임자 : 김유활 | 대표이사 : 이준원 | 사업자등록번호 : 118-81-03520 | 전화 : 02-3142-4151 | 팩스 : 02-338-3453 | 통신판매번호 : 제 2013-서울마포-1032호 copyright(c) HelloT all right reserved.