1. 배열 Decay(포인터 변환)란?
C나 C++에서 배열은 특정 조건에서 포인터로 변환되며, 이를 배열 Decay라고 부릅니다. 배열 Decay는 배열의 타입 정보와 크기 정보가 손실되고, 배열의 첫 번째 요소를 가리키는 포인터로 변환된다는 점에서 중요한 개념입니다.
2. 배열 Decay의 특징
- 타입 손실 배열
int numbers[5]
는 원래int[5]
타입이지만 Decay 후int*
타입으로 변환됩니다. - 크기 정보 손실 Decay된 배열은 원래 배열의 크기 정보를 잃습니다. 예를 들어:
int numbers[5];
printf("%zu\n", sizeof(numbers)); // 20 (5 * sizeof(int))
int *ptr = numbers;
printf("%zu\n", sizeof(ptr)); // 8 (포인터 크기)
- 배열과 포인터의 차이 배열은 메모리에서 고정된 크기를 가지는 데이터 블록이고, 포인터는 특정 메모리 주소를 가리킵니다. Decay는 이러한 배열을 포인터처럼 다룰 수 있도록 변환합니다.
3. 배열 Decay가 발생하는 상황
- 함수 호출 시 배열이 함수 인수로 전달될 때, 배열은 포인터로 Decay됩니다.
void func(int *arr) { /* ... */ }
int numbers[5];
func(numbers); // 배열 Decay 발생
- 포인터 연산 배열이 대입 연산자를 통해 포인터로 사용될 때 Decay가 발생합니다.
int numbers[5];
int *ptr = numbers; // Decay 발생
- 표현식에서 배열이 산술 연산 등에 사용되면 포인터로 변환됩니다.
int numbers[5] = {1, 2, 3, 4, 5};
int *ptr = numbers + 2; // numbers는 Decay되어 포인터로 작동
4. Decay가 발생하지 않는 경우
sizeof
연산 배열 자체가 전달되므로 Decay가 발생하지 않습니다.
int numbers[5];
printf("%zu\n", sizeof(numbers)); // 배열의 전체 크기 반환
- 참조 전달(C++만 해당) 배열을 참조로 전달하면 Decay를 방지할 수 있습니다.
void func(const int (&arr)[5]) {
printf("%zu\n", sizeof(arr)); // 배열의 크기 반환
}
int numbers[5];
func(numbers);
&
연산 배열 주소를 명시적으로 참조하면 Decay가 발생하지 않습니다.
int numbers[5];
int (*ptr)[5] = &numbers; // Decay 없음, 배열 전체를 참조
5. 배열 Decay의 주의사항
- 배열 크기 손실로 인해 메모리 초과 접근이 발생할 수 있습니다. 배열 크기가 필요한 경우 명시적으로 크기를 전달하거나 참조를 사용하는 것이 좋습니다.
- 함수 설계 시 신중함 필요: 배열이 포인터로 변환되므로, 함수 내부에서 배열의 크기를 추적해야 합니다.
결론
배열 Decay는 C와 C++에서 배열과 포인터 간의 유연한 사용을 가능하게 하는 중요한 메커니즘입니다. 하지만 크기 손실과 같은 한계도 있으므로 이를 이해하고 적절히 사용하는 것이 중요합니다.
Reference
https://stackoverflow.com/questions/1461432/what-is-array-to-pointer-conversion-aka-decay