Quick Syntax
함수 매개변수의 T arr[]와 T *arr는 같은 포인터 형태로 조정됩니다. 길이와 읽기·쓰기 권한은 별도 매개변수와 const로 계약합니다.
/* 읽기 전용: arr[0]부터 arr[n - 1]까지 읽을 수 있어야 한다. */
int sum_array(const int *arr, size_t n);
/* 수정 가능: 같은 범위를 쓸 수 있어야 한다. */
void clear_array(int *arr, size_t n);
/* C99: 적어도 n개 원소를 넘긴다는 호출자 계약 */
void normalize(size_t n, double arr[static n]);int arr[]와 int *arr는 함수 매개변수에서 같은 포인터가 됩니다. 그래서 sizeof arr로 길이를 복구할 수 없고, n == 0일 때 포인터를 어떻게 받을지도 API 계약으로 정합니다.
문법
함수 매개변수의 int arr[]는 겉보기만 배열이고, 실제로는 int *arr처럼 동작합니다.
void print_array(const int arr[], size_t n) {
for (size_t i = 0; i < n; i++) {
printf("%d\n", arr[i]);
}
}위 선언은 아래와 같은 의미로 읽어도 됩니다.
void print_array(const int *arr, size_t n);핵심은 두 가지입니다.
- 배열 전체가 함수로 복사되지 않습니다.
- 길이 정보는 자동으로 따라오지 않습니다.
C99부터 int arr[static n]는 호출자가 적어도 n개 원소에 접근할 수 있는 배열을 넘긴다는 계약을 표현할 수 있습니다. n == 0일 때 NULL을 허용하는 API라면 static n 표기보다 arr == NULL과 n의 관계를 함수 문서와 검사로 명시하는 편이 낫습니다.
전달 규칙
배열을 읽기만 하는 함수라면 const를 붙여 의도를 분명히 하는 편이 좋습니다.
int sum_array(const int *arr, size_t n) {
int total = 0;
for (size_t i = 0; i < n; i++) {
total += arr[i];
}
return total;
}반대로 원본을 수정하는 함수라면 const를 빼고, 길이 인자는 그대로 유지합니다.
void zero_array(int *arr, size_t n) {
for (size_t i = 0; i < n; i++) {
arr[i] = 0;
}
}다차원 배열은 두 번째 차원 크기가 주소 계산에 필요합니다. int **는 행 포인터 배열일 뿐 int matrix[rows][cols]와 같은 레이아웃이 아닙니다.
void clear_matrix(size_t rows, size_t cols, int matrix[rows][cols]);빠른 점검
함수 밖에서는 sizeof arr / sizeof arr[0]로 길이를 계산할 수 있습니다.
int data[] = {10, 20, 30, 40};
size_t n = sizeof(data) / sizeof(data[0]);
print_array(data, n);하지만 함수 안에서는 arr가 포인터처럼 보이므로 sizeof(arr)로 전체 길이를 구할 수 없습니다.
void wrong_size(int arr[]) {
size_t n = sizeof(arr) / sizeof(arr[0]); // 잘못된 길이
}주의할 점
함수 매개변수에 int arr[10]처럼 숫자를 적어도 호출자에게서 길이가 자동 보장되지는 않습니다. 그 표기는 문서적 힌트에 가깝고, 실제 안전성은 길이 인자와 호출 규약에 달려 있습니다.
참고 링크
2 sources