1. 문제 개요
C 언어에서 sizeof
연산자는 배열의 전체 크기를 반환할 수 있지만, 배열의 첫 번째 요소를 가리키는 포인터를 사용하면 배열 전체 크기를 알 수 없습니다. 이 글에서는 이 문제의 원인과 이를 해결하는 몇 가지 방법을 소개합니다.
2. 왜 포인터로 배열 크기를 알 수 없을까?
2.1 컴파일러와 포인터의 역할
배열과 포인터는 밀접하게 관련되어 있지만, 컴파일러는 포인터가 배열을 가리킨다는 사실을 알지 못합니다. 다음 코드를 예로 들어보겠습니다:
int days[] = {1, 2, 3, 4, 5};
int *ptr = days;
printf("%u\n", sizeof(days)); // 배열 크기 출력
printf("%u\n", sizeof(ptr)); // 포인터 크기 출력
위 코드에서:
sizeof(days)
는 배열의 전체 크기(예: 20바이트)를 반환합니다.sizeof(ptr)
는 포인터 크기(32비트 시스템에서는 4바이트)를 반환합니다.
포인터는 배열의 첫 번째 요소를 가리킬 뿐, 배열 자체에 대한 정보를 보유하지 않습니다.
3. 해결 방법
3.1 배열 크기를 별도로 저장하기
배열 크기를 직접 저장하는 방법이 가장 일반적입니다. 다음은 배열 크기를 변수로 저장하는 예제입니다:
int days[] = {1, 2, 3, 4, 5};
int size = sizeof(days) / sizeof(days[0]);
printf("Array size: %d\n", size);
동적 메모리 할당의 경우, 배열을 할당할 때 크기를 함께 저장해야 합니다:
size_t size = 5;
int *days = malloc(size * sizeof(int));
// 배열 크기(size)를 별도로 관리
3.2 배열 끝에 종료 마커 추가
특정 값(예: -1
)을 배열 끝에 추가하여 크기를 추적할 수도 있습니다:
int days[] = {1, 2, 3, 4, 5, -1};
int size = 0;
while (days[size] != -1) {
size++;
}
printf("Array size: %d\n", size);
이 방법은 배열에 고유하지 않은 값을 종료 마커로 사용할 때 문제가 될 수 있습니다.
3.3 동적 메모리와 메타데이터 활용
동적 메모리를 할당할 때, 크기를 별도로 저장하는 구조를 만들 수도 있습니다:
size_t size = 5;
int *days = malloc((size + 1) * sizeof(int));
days[0] = size; // 첫 번째 위치에 크기 저장
int *array = days + 1;
// 배열 크기를 찾는 방법
size_t array_size = days[-1];
이 접근법은 메모리 관리에 주의가 필요하며, free
를 호출할 때 원래 포인터를 사용해야 합니다.
4. 결론
C에서 포인터를 사용해 배열 크기를 알 수 없는 이유는 컴파일러가 포인터의 대상이 배열인지 알 수 없기 때문입니다. 배열 크기를 정확히 추적하려면 배열 크기를 별도로 저장하거나, 종료 마커를 추가하는 등의 방법을 활용해야 합니다. 이러한 원칙을 이해하면 메모리 관리와 코드의 안정성을 크게 향상시킬 수 있습니다.