개요
이 글에서는 C/C++ 프로그램에서 배열이 함수에 어떻게 전달되는지 살펴봅니다. 결론부터 말하면, C/C++에서 배열을 함수 인자로 넘기면 배열 전체가 복사되는 것이 아니라 배열의 첫 번째 요소를 가리키는 포인터(pointer) 형태로 전달됩니다. 이러한 현상을 흔히 '배열의 감쇠(array decay)'라고 부릅니다.
배열이 포인터로 전달되는 이유
배열 전체를 값으로 복사하면 메모리 사용량과 성능 면에서 비효율적일 수 있습니다. 그래서 C 언어 설계 당시부터 배열 이름은 대부분의 표현식에서 첫 번째 요소를 가리키는 포인터로 암묵적으로 변환되며, 함수 호출 시에도 마찬가지로 포인터만 전달됩니다. 따라서 함수 내부에서는 원본 배열의 실제 크기를 알 방법이 없습니다.
예제 코드
#include <stdio.h>
// 배열을 포인터 형태로 전달받는 함수
void fun(int arr[]) {
unsigned int n = sizeof(arr) / sizeof(arr[0]);
printf("\nfun() 내부의 배열 크기: %d", n);
}
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
unsigned int n = sizeof(arr) / sizeof(arr[0]);
printf("main() 내부의 배열 크기: %d", n);
fun(arr);
return 0;
}
실행 결과
main() 내부의 배열 크기: 8
fun() 내부의 배열 크기: 2
결과 분석
같은 배열을 다루는데 두 함수의 출력이 서로 다른 이유는 다음과 같습니다.
- main() 안에서: arr은 여전히 배열이므로 sizeof(arr)는 배열 전체 크기인 32바이트(8개 × 4바이트)를 반환합니다. 여기에 요소 하나의 크기인 4바이트를 나누면 8이 계산됩니다.
- fun() 안에서: 매개변수 arr은 사실상 int* 포인터입니다. 따라서 sizeof(arr)는 포인터 크기인 8바이트(64비트 시스템 기준)를 반환하고, 8 ÷ 4 = 2가 출력됩니다.
올바른 해결 방법
함수 내부에서 배열의 크기가 필요하다면, 배열과 함께 크기를 별도의 매개변수로 전달하는 것이 표준적인 방법입니다.
void fun(int arr[], unsigned int n) {
printf("배열 크기: %u\n", n);
}
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
unsigned int n = sizeof(arr) / sizeof(arr[0]);
fun(arr, n); // 크기 정보를 함께 전달
return 0;
}이처럼 C/C++에서 배열을 함수에 전달하면 항상 포인터로 변환된다는 점을 기억하고, 필요한 경우 크기 정보를 함께 넘겨주는 습관을 들이는 것이 안전한 코드 작성의 기본입니다.