다음과 같이 배열이 주어지면 배열의 크기와 원소의 크기를 통해 배열의 길이를 알 수 있다.
void main()
{
int arr[] = {1,2,3,4,5,6};
size_t arr_size = sizeof(arr)/sizeof(int); // 6
}
그런데 다음과 같이 함수의 인자로 배열을 넘겨받아서 위와 같이 계산하면 구할 수 없다.
void Foo(int arr[])
{
size_t arr_size = sizeof(arr)/sizeof(int); // 1
}
void main()
{
int arr[] = {1,2,3,4,5,6};
Foo(arr);
}
그 이유는 인자로 arr을 받을 때 배열이 아닌 포인터로 받기 때문이다. 즉 배열의 이름(주소)을 받는다. 그래서 분자가 배열의 크기가 아닌 포인터의 크기가 된다.
아래는 배열과 포인터를 인자로 받는 함수를 호출하는 코드를 디스어셈블 한 코드이다. 인자는 역순으로 전달되는데, ptr(포인터), arr(배열) 순으로 전달한다. 보면 ptr은 값(주소)을 그대로 스택에 저장하고, arr 또한 주소를 넘긴다.(lea)
정리해보면 정적 배열은 그 원소들이 미리 정해지므로, sizeof 연산자를 통해 컴파일 시간에 배열의 크기를 알 수 있다. (정확히는 sizeof는 인자가 정적 배열일 경우 내부적으로 배열의 크기를 계산하도록 되어있다고 들음) 그런데 함수에서 배열을 받으려면 첫 원소의 주소만 받는 것이 효율적이므로 당연히 포인터로 받을 수밖에 없다. 그리고 포인터가 가리키는 배열은 정적 배열과 달리 크기를 동적으로 할당받을 수 있기 때문에 그 크기를 미리 알 수가 없다. 때문에 문자열과 같이 널문자로 배열의 끝을 표시해주지 않는 이상 배열의 크기를 알 수 없다.
어떻게 보면 당연할 수 있는데 vector와 같은 것만 사용하다 보니 이런 기본적인 것을 잊고 있었다..
따라서 함수의 인자로 배열을 전달한다면 size 또한 함께 인자로 전달하거나, 문자열과 같이 배열의 끝을 알리는 값을 넣어 검사해주어야 한다.
'C,C++ > C++' 카테고리의 다른 글
[C++] VS2019 16.7 Ver. 안전성을 위한 새로운 코딩 규칙을 알아보자 (0) | 2020.09.11 |
---|---|
[C++] std::vector 컨테이너의 반복자를 통해 포인터(주소) 얻기 (0) | 2020.08.29 |
[C++] std::thread 기본 활용 방법을 알아보자 | mutex, condition_variable, 종료 방법 (2) | 2020.07.03 |
[C++] std::thread 생성에 대해 알아보자 (0) | 2020.06.26 |
특정 문자로 문자열 분리하기 | tokenizer (0) | 2020.06.23 |
댓글