본문 바로가기
CS/코딩테스트(C++)

[C++] 주소에 의한 호출, 참조에 의한 호출 (Call by Address, Reference), 포인터로 객체 멤버 접근하기

by CDCP 2024. 12. 30.

1. C++에서 함수 호출 시 인자를 넘겨줄 수 있는 방법들을 알아보겠습니다.

2. 포인터로 클래스의 멤버를 접근할 때 사용하는 연산자(->, .)의 차이를 정리해 보겠습니다.


값에 의한 호출?

  • call by value
  • 함수 호출 시 인자로 들어온 값을 복사해서 사용
  • 호출된 함수에서 연산을 거쳐도 인자에 영향을 주지 않음

예)

void swap(int x, int y) // 함수 구현부
{
	// 내용
}
swap(input1, input2); // 함수 호출 형태

 

주소에 의한 호출?

  • call by address
  • 새롭게 변수를 생성하고 그곳에 값을 저장하는 것이 아니므로 자원을 절약할 수 있음. (메모리, 시간)
  • 함수 호출 시 주소 값을 인자로 받음
  • 호출할 함수의 매개변수를 포인터 형태로 구현
  • 호출된 함수에서 들어온 인자로 연산을 거치면 함수 바깥에도 영향을 줄 수 있음

예)

void swap(int *x, int *y) // 매개변수가 포인터 형태
{
	// 내용
}
swap(&input1, &input2); // 주소를 인자로 넘김

 

int *x = &input1; 의 형태입니다.

포인터 x는 input의 주소를 저장하게 됩니다. 이후 역참조 연산자(*)를 사용하여, 포인터가 가리키는 변수 값을 접근할 수 있습니다. (*x)

 

참조에 의한 호출?

  • call by reference
  • C++에서만 사용 가능 (C는 불가)
  • 함수 호출 시 인자로 들어온 값을 참조함
  • 주소에 의한 호출과 비슷하지만 코드 가독성이 높아지고 실수할 위험 감소

예)

void swap(int &x, int &y) // 매개변수에 참조 연산자 사용 (주소를 받는 느낌)
{
	// 내용
}
swap(input1, input2); // 값에 의한 호출과 같은 형태

 

->와 .?

  • -> 연산자는 포인터를 통해 클래스의 멤버에 접근할 때 사용
  • . 연산자는 클래스의 멤버에 직접 접근할 때 사용
  • 포인터 a가 객체를 가리키고 있을 때 (*a).b와 a->b는 동일한 표현

예)

// string 클래스를 예로 들면
string str = "test";
string *pstr = &str;

cout << "*pstr : " << *pstr << endl; // test
cout << "(*pstr).size() : " << (*pstr).size() << endl; // 4
cout << "pstr->size() : " << pstr->size() << endl; // 4

- '참조에 의한 호출'을 '주소에 의한 호출'로 변환해 보면서, 클래스에 포인터를 사용할 때 헷갈리는 부분이 있더라고요. 정리할 겸 같이 넣었습니다.


전체 소스 코드 (~에 의한 호출)

#include <iostream>
using namespace std;

void swap(int x, int y) // 값에 의한 호출
{
	cout << "sawp() 호출\n";
	int tmp = x;
	x = y;
	y = tmp;
}

void swap2(int *x, int *y) // 주소에 의한 호출
{
	cout << "sawp2() 호출\n";
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void swap3(int &x, int &y) // 참조에 의한 호출
{
	cout << "sawp3() 호출\n";
	int tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int input1, input2;
	
	// 값에 의한 호출
	input1 = 2, input2 = 5;
	cout << input1 << " " << input2 << endl;
	swap(input1, input2);
	cout << input1 << " " << input2 << endl << endl;

	// 주소에 의한 호출
	input1 = 4, input2 = 7;
	cout << input1 << " " << input2 << endl;
	swap2(&input1, &input2);
	cout << input1 << " " << input2 << endl << endl;

	// 참조에 의한 호출
	input1 = 5, input2 = 9;
	cout << input1 << " " << input2 << endl;
	swap3(input1, input2);
	cout << input1 << " " << input2 << endl;
	
	return 0;
}

 

전체 소스 코드 (포인터로 클래스 접근하기)

#include <iostream>
#include <string>
using namespace std;

int main()
{
	string str = "test";
	string* pstr = &str;

	cout << "str : " << str << endl; // test
	cout << "str.size() : " << str.size() << endl; // 4
	cout << "&str : " << &str << endl; // str의 주소값
	cout << "pstr : " << pstr << endl; // str의 주소값
	cout << "*pstr : " << *pstr << endl; // test
	cout << "(*pstr).size() : " << (*pstr).size() << endl; // 
	cout << "pstr->size() : " << pstr->size() << endl; // 
	return 0;
}

참고 자료

https://codemasterkimc.tistory.com/14 - c++에서 ->와 .의 차이

https://brightwon.tistory.com/7 - call by value, address, reference

https://www.acmicpc.net/board/view/146295 - 참조에 의한 호출이 주는 자원 감소 효과