C/C++ 프로그래밍에서 배열의 크기를 구할 때 일반적으로 sizeof 연산자를 사용하지만, 포인터 산술(pointer arithmetic)을 활용하면 sizeof 없이도 배열의 크기를 구할 수 있습니다. 이 글에서는 그 원리와 구현 방법을 자세히 살펴보겠습니다.
동작 원리
이 기법은 배열과 배열의 주소에 대한 포인터의 성질을 이용합니다. 핵심 아이디어는 다음과 같습니다.
- &a : 배열 전체를 가리키는 포인터로, 배열 이름
a와 동일한 메모리 주소를 가리킵니다. - &a + 1 : 배열 전체 크기만큼 이동하므로, 배열의 끝 바로 다음 메모리 주소를 가리킵니다.
- *(&a + 1) : 역참조(dereferencing)하면 마지막 요소 다음 위치의 주소를 얻을 수 있습니다.
- *(&a + 1) - a : 첫 번째 요소의 주소를 빼면 두 주소 사이의 요소 개수, 즉 배열의 길이가 됩니다.
여기서 중요한 점은 &a가 '배열 전체' 타입의 포인터이기 때문에 1을 더하면 배열 크기만큼 건너뛴다는 것입니다. 반면 a는 첫 번째 요소를 가리키므로 두 값의 차이는 정확히 배열의 요소 개수가 됩니다.
예제 코드
#include <iostream>
using namespace std;
int main() {
int a[] = {6,7,5,3,1,4,2,10,9};
int s = *(&a + 1) - a;
cout << "배열의 요소 개수는 " << s;
return 0;
}실행 결과
배열의 요소 개수는 9
주의 사항
이 방법은 배열이 함수 내에서 선언된 경우에만 유효합니다. 배열을 함수의 매개변수로 전달하면 배열이 포인터로 decay(붕괴)되기 때문에 &a + 1 계산이 더 이상 올바르게 동작하지 않습니다. 따라서 실무에서는 가독성과 안전성을 위해 sizeof(a) / sizeof(a[0]) 또는 C++11 이상에서 제공하는 std::size(), std::array 컨테이너를 사용하는 것이 권장됩니다.