Q 6.20
정적 또는 동적으로 할당된 다차원 배열을 함수에 전달할때, 서로 구별하지
않고 쓸 수 있는 방법이 있을까요?
Answer 완벽한 방법은 없습니다. 다음 선언이 있다고 할 때:
int array[NROWS][NCOLUMNS];
int **array1; /* ragged */
int **array2; /* contiguous */
int *array3; /* "flattened" */
int (*array4)[NCOLUMNS];
int (*array5)[NROWS][NCOLUMNS]
포인터들은 질문 6.16에 나온 것처럼 초기화되어 있다고 가정하고 함수 선
언은 다음과 같다고 가정합니다:
void f1a(int a[][NCOLUMNS], int nrows, int ncolumns);
void f1b(int (*a)[NCOLUMNS], int nrows, int ncolumns);
void f2(int *aryp, int nrows, int ncolumns);
void f3(int **pp, int nrows, int ncolumns);
이때, f1a()와 f1b()는 일반적인 이차원 배열을 인자로 받으며, f2()는 펼
쳐진(flattened) 이차원 배열을 인자로 받으며, f3()은 ‘포인터를 가리키는
포인터’를 인자로 받습니다 (질문 6.18과 6.19를 참고). 따라서 다음과 같
이 호출할 수 있습니다:
f1a(array, NROWS, NCOLUMNS);
f1b(array, NROWS, NCOLUMNS);
f1a(array4, nrows, NCOLUMNS);
f1b(array4, nrows, NCOLUMNS);
f1a(*array5, NROWS, NCOLUMNS);
f1b(*array5, NROWS, NCOLUMNS);
f2(&array[0][0], NROWS, NCOLUMNS);
f2(*array, NROWS, NCOLUMNS);
f2(*array2, nrows, ncolumns);
f2(array3, nrows, ncolumns);
f2(*array4, nrows, NCOLUMNS);
f2(**array5, NROWS, NCOLUMNS);
f3(array1, nrows, ncolumns);
f3(array2, nrows, ncolumns);
대부분의 컴퓨터에서 다음의 호출들도 동작할 것이나, 복잡한 캐스트가 필
요하고, 동적인 ncolumns가 (대개 변수) 정적인 NCOLUMNS와 (대개 매
크로 상수) 일치할 경우에만 쓸 수 있습니다:
f1a((int (*)[NCOLUMNS])(*array2), nrows, ncolumns);
f1a((int (*)[NCOLUMNS])(*array2), nrows, ncolumns);
f1b((int (*)[NCOLUMNS])array3, nrows, ncolumns);
f1b((int (*)[NCOLUMNS])array3, nrows, ncolumns);
동적 또는 정적으로 할당한 배열 모두에 편하게 쓸 수 있는 함수는 f2입니
다. 그러나 “ragged” 형태로 만든 배열인 array1에는 동작하지 않을 수도
있습니다. 그리고 &array[0][0]을 (또는 *array) f2()에 전달하는 것은
표준에 정확히 맞지 않습니다; 질문 6.19를 참고하기 바랍니다.
만약 위에 나열한 호출이 어떻게 동작하고 어떻게 작성되는지 이해한다면,
그리고 왜 다른 조합이 동작하지 않는지 않다면, 여러분은 C 언어에서 배
열과 포인터에 대해 매우 잘 이해하고 있다고 말할 수 있습니다.
위에서 어떤 것을 쓸 것인지 결정하는데 고민이 된다면, 질문 6.16에 나온
것처럼, 다양한 크기를 가지는 다차원 배열을 모두 동적으로 만드는 것이 한
방법이 될 수 있습니다 — 만약 모든 배열이 질문 6.16의 array1, array2
처럼 만들어 진다면 — 모든 함수는 f3()처럼 만들어야 합니다.
정적 또는 동적으로 할당된 다차원 배열을 함수에 전달할때, 서로 구별하지
않고 쓸 수 있는 방법이 있을까요?
Answer 완벽한 방법은 없습니다. 다음 선언이 있다고 할 때:
int array[NROWS][NCOLUMNS];
int **array1; /* ragged */
int **array2; /* contiguous */
int *array3; /* "flattened" */
int (*array4)[NCOLUMNS];
int (*array5)[NROWS][NCOLUMNS]
포인터들은 질문 6.16에 나온 것처럼 초기화되어 있다고 가정하고 함수 선
언은 다음과 같다고 가정합니다:
void f1a(int a[][NCOLUMNS], int nrows, int ncolumns);
void f1b(int (*a)[NCOLUMNS], int nrows, int ncolumns);
void f2(int *aryp, int nrows, int ncolumns);
void f3(int **pp, int nrows, int ncolumns);
이때, f1a()와 f1b()는 일반적인 이차원 배열을 인자로 받으며, f2()는 펼
쳐진(flattened) 이차원 배열을 인자로 받으며, f3()은 ‘포인터를 가리키는
포인터’를 인자로 받습니다 (질문 6.18과 6.19를 참고). 따라서 다음과 같
이 호출할 수 있습니다:
f1a(array, NROWS, NCOLUMNS);
f1b(array, NROWS, NCOLUMNS);
f1a(array4, nrows, NCOLUMNS);
f1b(array4, nrows, NCOLUMNS);
f1a(*array5, NROWS, NCOLUMNS);
f1b(*array5, NROWS, NCOLUMNS);
f2(&array[0][0], NROWS, NCOLUMNS);
f2(*array, NROWS, NCOLUMNS);
f2(*array2, nrows, ncolumns);
f2(array3, nrows, ncolumns);
f2(*array4, nrows, NCOLUMNS);
f2(**array5, NROWS, NCOLUMNS);
f3(array1, nrows, ncolumns);
f3(array2, nrows, ncolumns);
대부분의 컴퓨터에서 다음의 호출들도 동작할 것이나, 복잡한 캐스트가 필
요하고, 동적인 ncolumns가 (대개 변수) 정적인 NCOLUMNS와 (대개 매
크로 상수) 일치할 경우에만 쓸 수 있습니다:
f1a((int (*)[NCOLUMNS])(*array2), nrows, ncolumns);
f1a((int (*)[NCOLUMNS])(*array2), nrows, ncolumns);
f1b((int (*)[NCOLUMNS])array3, nrows, ncolumns);
f1b((int (*)[NCOLUMNS])array3, nrows, ncolumns);
동적 또는 정적으로 할당한 배열 모두에 편하게 쓸 수 있는 함수는 f2입니
다. 그러나 “ragged” 형태로 만든 배열인 array1에는 동작하지 않을 수도
있습니다. 그리고 &array[0][0]을 (또는 *array) f2()에 전달하는 것은
표준에 정확히 맞지 않습니다; 질문 6.19를 참고하기 바랍니다.
만약 위에 나열한 호출이 어떻게 동작하고 어떻게 작성되는지 이해한다면,
그리고 왜 다른 조합이 동작하지 않는지 않다면, 여러분은 C 언어에서 배
열과 포인터에 대해 매우 잘 이해하고 있다고 말할 수 있습니다.
위에서 어떤 것을 쓸 것인지 결정하는데 고민이 된다면, 질문 6.16에 나온
것처럼, 다양한 크기를 가지는 다차원 배열을 모두 동적으로 만드는 것이 한
방법이 될 수 있습니다 — 만약 모든 배열이 질문 6.16의 array1, array2
처럼 만들어 진다면 — 모든 함수는 f3()처럼 만들어야 합니다.