본문 바로가기

💻 내 소개 안녕하세요 엄청짱 프로그래머 손다빈 입니다.
  • 나이 : 96년생
  • 특이사항 : MZ세대, INFJ, 오른손잡이, 아이폰 유저
  • 좋아하는 음식 : 햄버거피자치킨솥뚜껑삼겹살떡볶이오튀김밥
  • 취미 : 개발, Programming, 코딩, 프로그래밍, Coding

🥷기술
Unity
Godot
Cpp
Javascript
D3
Vue

🐱 우리집 고양이 소개
츄르 먹은 후 츄르 먹기 전
  • 이름 : 콜라
  • 나이 : 8살
  • 종 : Nado moreum

📱 개인 프로젝트
🏢 참여한 프로젝트
빌런즈 Life is Pair 도씨어부키우기 직장상사혼내주기 서바이벌빙고 SlitherCoin

🌱 내 잔디밭

배열과 포인터는 다릅니다. 본문

글 묶음/지옥에서 온 C++

배열과 포인터는 다릅니다.

초긍정 개발자 다빈맨 2019. 2. 14. 05:17


| 배열과 포인터는 다릅니다.



여러 C/C++ 언어 기본서에서 포인터에 대해서 다룰 때 배열의 이름과 포인터를 완전히 동일하게 취급하곤 합니다. 실제로 배열의 이름으로 메모리에 접근할 때, 포인터와 동일하게 작동하듯 보이기 때문에 이렇게 이해하는 것도 무리는 아닙니다. 하지만 이게 배열의 이름이 정말로 포인터와 같은 타입이기 때문에 가능한 일이 아니라는 겁니다.

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

int main()
{
	int arr[] = { 1, 2, 3, 4 };
	int* ptrArr = arr;		 // 포인터로 형 변환을 허용!

	cout << typeid(arr).name() << endl; // 타입은 int [4]
	cout << typeid(ptrArr).name() << endl; // 타입은 int *

	return 0;
}

위 코드를 실행해보면 알 수 있듯이 배열의 이름은 arr 과 포인터 변수인 ptrArr 은 각각 다른 타입을 가집니다.  C++에서 배열의 이름이나 함수의 이름의 경우, 포인터형으로 형 변환을 허용합니다. 하지만 포인터로 변환될 때 생기는 부작용이 하나가 있습니다. 바로 배열의 길이정보를 잃게 되는 것이죠. 타입을 출력해보면 알겠지만 배열의 이름인 arr 은 길이정보를 포함해서 출력되지만 ptrArr 은 길이정보를 잃고, 단지 포인터라는 정보만 담고 있습니다.


이렇게 정보를 잃고 포인터로 형 변환될 때, 포인터로 Decay(부식)된다고 합니다. 


※ <typeinfo> 헤더파일의 typeid() 를 이용하면 값의 타입을 출력해볼 수 있습니다.




| 포인터로 부식(Decay)되어 정보를 잃는게 싫다면, 참조를 사용하면 됩니다.


C++의 참조는 같은 메모리의 이름을 하나 더 부여해서 메모리에 접근할 수 있는 방식이기 때문에 타입을 그대로 가져올 수 있습니다.

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

int main()
{
	int arr[] = { 1, 2, 3, 4 };
	int (&refArr)[4] = arr;

	cout << typeid(arr).name() << endl;		//int [4]
	cout << typeid(refArr).name() << endl;		//int [4]

	return 0;
}

참조를 사용하면 위 코드와 같이 포인터로 부식(Decay)되지 않고 기존의 배열 타입으로 유지할 수 있습니다. 여기서는 배열의 길이를 4로 알고 있어야 하기 때문에 이게 얼마나 도움이 되는지 와닿지 않지만 만약 템플릿을 이용한다면 다음과 같은 응용이 가능합니다.

template< typename T, size_t N >
size_t ArraySize(T(& const)[N])
{
    return N;
}

포인터로 배열을 매개변수로 전달받는 경우, 포인터로 부식(Decay)되어 길이 정보를 받지 못하기에 보통 길이정보를 함수로 같이 전달하곤 했습니다. 하지만 템플릿을 이용해서 참조로 전달받는다면 길이정보를 스스로 추론하도록 할 수 있습니다.

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

template< typename T, size_t N >
size_t ArraySize(T(& const)[N])
{
    return N;
}

int main()
{
	int arr[] = { 1, 2, 3, 4 };
	int (&refArr)[4] = arr;

	cout << typeid(arr).name() << endl;		//int [4]
	cout << typeid(refArr).name() << endl;		//int [4]
	cout << ArraySize(refArr) << endl;		//4

	return 0;
}

역시 참조는 언제나 좋은 정답을 주네요.