고정 크기
1. 참조로 전달
template <size_t rows, size_t cols>
void process_2d_array_template(int (&array)[rows][cols])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
C ++에서는 차원 정보를 잃지 않고 참조로 배열을 전달하는 것이 가장 안전합니다. 호출자가 잘못된 차원을 전달하는 것에 대해 걱정할 필요가 없으므로 (일치하지 않을 때 컴파일러 플래그). 그러나 동적 (프리 스토어) 배열에서는 불가능합니다. 자동 ( 보통 스택 리빙 ) 배열에서만 작동합니다. 즉, 차원은 컴파일 타임에 알려야합니다.
2. 포인터로 전달
void process_2d_array_pointer(int (*array)[5][10])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < 5; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << (*array)[i][j] << '\t';
std::cout << std::endl;
}
}
이전 방법과 동등한 C는 배열을 포인터로 전달합니다. 이것은 배열의 붕괴 포인터 유형 (3) 을 전달하는 것과 혼동되어서는 안됩니다.이 유형 은 일반적이지만 널리 사용되는 방법이지만이 방법보다 안전하지만 유연합니다. (1) 과 마찬가지로 배열의 모든 차원이 고정되어 컴파일 타임에 알려진 경우이 방법을 사용하십시오. 함수를 호출 할 때 process_2d_array_pointer(&a)
첫 번째 요소의 주소가 아닌 배열의 주소가 decay 로 전달되어야합니다 process_2d_array_pointer(a)
.
가변 크기
이것들은 C에서 상속되었지만 덜 안전합니다. 컴파일러는 확인할 방법이 없으므로 호출자가 필요한 크기를 전달합니다. 이 함수는 발신자가 차원으로 전달한 내용 만 뱅킹합니다. 길이가 다른 배열을 변하지 않고 전달할 수 있기 때문에 위의 것보다 더 유연합니다.
C의 함수에 직접 배열을 전달하는 것과 같은 것은 없다는 것을 기억해야한다. [C ++에서는 참조 (1) 로 전달 될 수있다 ]; (2) 배열 자체가 아닌 배열에 포인터를 전달합니다. 항상 배열을 그대로 전달하는 것은 포인터의 복사 특성으로 인해 포인터 복사 작업이 용이 한 포인터 복사 작업이 됩니다.
3. 소멸 된 유형으로 포인터를 전달 (값)
// int array[][10] is just fancy notation for the same thing
void process_2d_array(int (*array)[10], size_t rows)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
int array[][10]
허용 되지만 위의 구문은 식별자 array
가 10 개의 정수 배열에 대한 단일 포인터 라는 것을 분명히하기 때문에 위의 구문에 대해서는 권장하지 않습니다. 이 구문 은 2D 배열처럼 보이지만 동일한 포인터입니다. 10 개의 정수 배열 여기서 우리는 단일 행의 요소 수 (여기서는 열 크기, 10)를 알고 있지만 행 수는 알 수 없으므로 인수로 전달됩니다. 이 경우 2 차원이 10이 아닌 배열에 대한 포인터가 전달 될 때 컴파일러가 플래그를 지정할 수 있으므로 안전성이 약간 있습니다. 첫 번째 치수는 변화하는 부분이므로 생략 할 수 있습니다. 첫 번째 차원 만 생략 할 수있는 이유 에 대한 근거 는 여기를 참조하십시오 .
포인터로 포인터로 전달
// int *array[10] is just fancy notation for the same thing
void process_pointer_2_pointer(int **array, size_t rows, size_t cols)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
또 다른 구문은와 int *array[10]
동일합니다 int **array
. 이 구문에서는 [10]
포인터로 쇠퇴 하여 이므로 무시됩니다 int **array
. 아마도 전달 된 배열에 열이 10 개 이상 있어야 행 번호가 필요하다는 것은 호출자에게 신호 일 것입니다. 어쨌든 컴파일러는 길이 / 크기 위반에 플래그를 지정하지 않습니다 (전달 된 유형이 포인터에 대한 포인터인지 확인). 따라서 매개 변수로 행 및 열 수를 모두 필요로합니다.
참고 : (4)는 형식 검사가 거의없고 가장 불편하기 때문에 가장 안전 하지 않은 옵션 입니다. 합법적으로이 함수에 2D 배열을 전달할 수는 없습니다. C-FAQ 비난은 하기의 일반적인 대안 int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
은 같은 잠재적으로 정의되지 않은 동작이 발생할 수 인해 어레이로 평탄화한다. 이 방법으로 배열을 전달하는 올바른 방법은 불편한 부분을 가져옵니다. 즉, 각 요소가 실제 전달 될 배열의 각 행을 가리키는 포인터의 추가 (대리) 배열이 필요합니다. 그런 다음이 대리자는 함수로 전달됩니다 (아래 참조). 더 안전하고 깨끗하며 아마도 더 빠른 위의 방법과 동일한 작업을 수행하기 위해이 모든 것.
위의 기능을 테스트하는 드라이버 프로그램은 다음과 같습니다.
#include <iostream>
// copy above functions here
int main()
{
int a[5][10] = { { } };
process_2d_array_template(a);
process_2d_array_pointer(&a); // <-- notice the unusual usage of addressof (&) operator on an array
process_2d_array(a, 5);
// works since a's first dimension decays into a pointer thereby becoming int (*)[10]
int *b[5]; // surrogate
for (size_t i = 0; i < 5; ++i)
{
b[i] = a[i];
}
// another popular way to define b: here the 2D arrays dims may be non-const, runtime var
// int **b = new int*[5];
// for (size_t i = 0; i < 5; ++i) b[i] = new int[10];
process_pointer_2_pointer(b, 5, 10);
// process_2d_array(b, 5);
// doesn't work since b's first dimension decays into a pointer thereby becoming int**
}