함수 매개변수에서 int data[]는 배열 전체를 값으로 받는 선언이 아닙니다. C의 매개변수 선언 규칙에 따라 해당 매개변수는 int *data와 같이 조정됩니다. 따라서 함수 안의 sizeof data는 원래 배열의 크기가 아니라 포인터 크기를 반환합니다.

배열 원소 수가 필요하면 호출자가 길이를 별도 인자로 전달하거나, 배열 길이를 계산할 수 있는 지점에서 계산해야 합니다. 포인터 크기는 구현에 따라 달라지므로 특정 바이트 수로 외우지 않습니다.

함수 경계를 지나면 배열의 크기 정보가 전달되지 않습니다

호출부에서 int values[5]는 다섯 원소를 가진 배열입니다. 하지만 inspect(values)처럼 함수에 전달할 때 배열 식은 첫 원소를 가리키는 포인터로 변환됩니다. 함수의 매개변수 선언 int data[]도 포인터 매개변수로 조정되므로, 그 자리에서 배열의 다섯 칸이 유지된다고 볼 수 없습니다. C11의 sizeof 연산자는 배열 피연산자에는 전체 배열 크기를, 포인터 피연산자에는 포인터 객체 크기를 적용합니다. 두 식의 모양이 비슷해도 평가 지점의 자료형이 다르면 결과의 뜻이 달라집니다.

같은 이름의 sizeof도 지점에 따라 답이 달라집니다

교육용 예시이며 공식 기출이나 유료 카드 문항이 아닙니다. 포인터 크기의 숫자는 일부러 고정하지 않았습니다.
void inspect(int data[]) {
    size_t bytes = sizeof data;   // sizeof(int *)와 같은 범주
}
int values[5];
size_t whole = sizeof values;
size_t count = sizeof values / sizeof values[0];
inspect(values);
sizeof가 받는 식의 자료형을 먼저 봅니다
표현식 위치그 지점의 형식뜻
sizeof valuesint[5] 배열배열 전체 바이트 수
sizeof values[0]int 원소원소 하나의 바이트 수
sizeof data조정된 int * 매개변수포인터 객체의 바이트 수

호출부의 나눗셈 sizeof values / sizeof values[0]는 배열 식 전체가 호출부에 남아 있어 원소 수 5를 구합니다. 함수 안에서는 data가 포인터이므로 같은 나눗셈을 반복해도 배열 길이를 계산하지 못합니다. 포인터 크기가 int 한 칸보다 같거나 크다는 식의 고정 가정도 하지 마세요. 구현별 크기와 정렬은 언어 규칙이 보장하는 배열 길이와 다른 정보입니다.

길이를 전달할 때는 계약을 분명히 씁니다

  1. 배열 원소 수가 필요한 위치가 호출부인지 함수 내부인지 확인합니다.
  2. 호출부라면 sizeof 배열 / sizeof 배열[0]을 계산합니다.
  3. 함수 내부라면 포인터와 함께 원소 수를 별도 매개변수로 전달합니다.
  4. 함수 안의 sizeof 대상이 배열인지 포인터인지 선언과 함께 확인합니다.

배열 표기와 배열 객체를 같은 뜻으로 보면 틀립니다

매개변수에 대괄호가 남아 있다는 이유로 그 함수가 배열 길이를 자동으로 안다고 착각하기 쉽습니다. 대괄호 표기는 매개변수 선언 문법의 배열 형태일 뿐, 호출자가 가진 배열 객체의 전체 크기를 함수에 복사하지 않습니다. 반대로 호출부 배열 자체에 sizeof를 적용할 때까지 언제나 포인터로 바뀐다고 말해도 안 됩니다. 배열 식은 sizeof처럼 변환 예외가 있는 문맥에서는 배열 형식을 유지합니다. 문제를 풀 때에는 식의 이름보다 선언과 사용 문맥을 먼저 확인하세요.

함수 안에서 배열 원소 수가 필요하면 선언만으로 길이를 알아낼 수 있다고 기대하지 말고, 호출 규약에 길이를 포함합니다. 예를 들어 포인터와 size_t count를 함께 전달하고 함수는 count를 반복 범위로 사용합니다. 호출부에서 배열 크기를 계산할 수 있을 때 원소 크기로 나누어 count를 만들 수 있습니다. 포인터로 매개변수가 조정되는 규칙과 그 포인터가 가리키는 유효 원소 수는 서로 다른 정보입니다. 잘못된 count를 전달하면 함수가 범위를 넘을 수 있으므로 호출자와 함수 사이에서 그 값이 맞는지 보장해야 합니다.

정답을 가리고 확인해 보세요

이 글을 위해 만든 학습 예시이며 공식 기출문제나 판매 카드의 인용이 아닙니다.

int x[7]을 f(int a[])에 전달한 뒤 f 안의 sizeof a는 무엇을 측정하나요?

정답과 해설 확인조정된 포인터 매개변수 a의 크기를 측정합니다. 배열 원소 수 7을 알려면 길이를 별도 인자로 전달해야 합니다.

C11 매개변수 배열 선언은 포인터 매개변수로 조정됩니다. 호출부의 배열 크기 정보는 함수의 포인터 매개변수에 자동으로 보존되지 않습니다.