프로젝트에서 누군가 다음 줄을 썼습니다.
double (*e)[n+1] = malloc((n+1) * sizeof(*e));
이것은 아마도 (n + 1) * (n + 1) double의 2 차원 배열을 생성합니다.
아마 지금까지 내가 물었다 아무도 정확히, 이것은 무엇을 말해 줄 수 없었다 때문에, 나는 말,도 아니다 유래 어디서 왜 작동합니다 (주장, 그것은 않는,하지만 난 아직 구입하고 있지 않다).
아마도 나는 분명한 것을 놓치고 있지만 누군가가 위의 줄을 설명해 줄 수 있다면 감사 할 것입니다. 왜냐하면 개인적으로 우리가 실제로 이해하는 것을 사용한다면 훨씬 나아질 것이기 때문입니다.
답변
변수 e
는 n + 1
유형 요소의 배열에 대한 포인터 double
입니다.
역 참조 연산자를 e
사용하면 e
” n + 1
유형 의 요소 배열”인 기본 유형이 제공 double
됩니다.
malloc
호출은 단순히의 염기 형을 얻어 e
(상술)로하고, 승산을 사이즈를 취득 n + 1
하고, 해당 크기를 전달하는 malloc
기능. 기본적으로 n + 1
의 n + 1
요소 배열 배열을 할당합니다 double
.
답변
이것은 2D 배열을 동적으로 할당해야하는 일반적인 방법입니다.
e
유형 배열에 대한 배열 포인터double [n+1]
입니다.sizeof(*e)
따라서 한double [n+1]
배열 의 크기 인 pointed-at 유형의 유형을 제공합니다 .n+1
이러한 어레이를 위한 공간을 할당 합니다.e
이 배열 배열의 첫 번째 배열을 가리 키 도록 배열 포인터 를 설정합니다 .- 이를 통해
e
as 를 사용e[i][j]
하여 2D 배열의 개별 항목에 액세스 할 수 있습니다.
개인적으로이 스타일이 훨씬 읽기 쉽다고 생각합니다.
double (*e)[n+1] = malloc( sizeof(double[n+1][n+1]) );
답변
이 관용구는 자연스럽게 1D 배열 할당에서 벗어납니다. 임의의 유형의 1D 배열을 할당하는 것으로 시작하겠습니다 T
.
T *p = malloc( sizeof *p * N );
간단 하죠? 표현은 *p
유형이 T
있으므로, sizeof *p
같은 결과를 제공 sizeof (T)
그래서 우리는 충분한 공간을 할당하고, N
의 – 요소 배열 T
. 이것은 모든 유형T
에 해당됩니다 .
이제 T
와 같은 배열 유형으로 대체합시다 R [10]
. 그러면 우리의 할당은
R (*p)[10] = malloc( sizeof *p * N);
여기서 의미 는 1D 할당 방법 과 정확히 동일 합니다. 변경된 것은 p
. 대신 T *
지금 R (*)[10]
입니다. 식은 *p
형 갖는 T
타입 R [10]
이므로 sizeof *p
동등 sizeof (T)
동등하다 sizeof (R [10])
. 그래서 우리는 충분한 공간을 할당하고 N
로 10
의 요소 배열 R
.
우리가 원한다면 이것을 더 나아갈 수 있습니다. R
자체가 배열 유형 이라고 가정 합니다 int [5]
. 그것을 대체 R
하고 우리는
int (*p)[10][5] = malloc( sizeof *p * N);
같은 거래는 – sizeof *p
과 동일 sizeof (int [10][5])
하고, 우리는을 개최 메모리 충분한 크기의 연속 된 덩어리를 할당하는 바람 N
에 의해 10
에 의해 5
배열 int
.
이것이 할당 측면입니다. 액세스 측은 어떻습니까?
기억 []
첨자 동작되는 정의 포인터 연산의 관점에서 : a[i]
으로 정의 *(a + i)
1 . 따라서 첨자 연산자는 []
암시 적 으로 포인터를 역 참조합니다. 경우 p
에 대한 포인터 T
를 명시 적으로 단항으로 역 참조하여 지적-가치 중 하나, 액세스 할 수있는 *
운영자 :
T x = *p;
또는[]
아래 첨자 연산자 를 사용하여 :
T x = p[0]; // identical to *p
따라서 배열p
의 첫 번째 요소를 가리키는 경우 포인터의 아래 첨자를 사용하여 해당 배열의 모든 요소에 액세스 할 수 있습니다 .p
T arr[N];
T *p = arr; // expression arr "decays" from type T [N] to T *
...
T x = p[i]; // access the i'th element of arr through pointer p
이제 대체 작업을 다시 수행하고 T
배열 유형으로 대체하겠습니다 R [10]
.
R arr[N][10];
R (*p)[10] = arr; // expression arr "decays" from type R [N][10] to R (*)[10]
...
R x = (*p)[i];
하나의 즉각적인 차이점; p
아래 첨자 연산자를 적용하기 전에 명시 적으로 역 참조 합니다. 우리는에 첨자를 붙이고 싶지 않고 p
, 어떤 p
점 (이 경우 배열 arr[0]
)을 가리키는 지에 첨자를 씁니다 . 단항 *
은 아래 첨자 []
연산자 보다 우선 순위가 낮기 때문에 괄호를 사용하여 명시 적 p
으로 *
. 그러나 위에서 *p
는과 동일 p[0]
하므로 다음으로 대체 할 수 있습니다.
R x = (p[0])[i];
아니면 그냥
R x = p[0][i];
따라서 p
2D 배열을 가리키는 경우 p
다음과 같이 해당 배열을 인덱싱 할 수 있습니다 .
R x = p[i][j]; // access the i'th element of arr through pointer p;
// each arr[i] is a 10-element array of R
상기 및 치환과 같은 결론이 촬영 R
으로 int [5]
:
int arr[N][10][5];
int (*p)[10][5]; // expression arr "decays" from type int [N][5][10] to int (*)[10][5]
...
int x = p[i][j][k];
이 작품 그냥 같은 경우 p
규칙적인 배열을 포인트하거나 메모리를 가리키는 경우를 통해 할당 malloc
.
이 관용구에는 다음과 같은 이점이 있습니다.
- 간단합니다. 단편적인 할당 방법과 달리 코드 한 줄만
T **arr = malloc( sizeof *arr * N ); if ( arr ) { for ( size_t i = 0; i < N; i++ ) { arr[i] = malloc( sizeof *arr[i] * M ); } }
- 할당 된 배열의 모든 행은 * 연속적 *이며, 위의 단편적인 할당 방법의 경우에는 해당되지 않습니다.
- 어레이 할당 해제는
free
. 다시 말하지만, 할당을 해제arr[i]
하기 전에 각 할당을 해제해야하는 증분 할당 방법에서는 사실이 아닙니다arr
.
힙이 심하게 조각화되어 메모리를 연속 청크로 할당 할 수 없거나 각 행이 다른 길이를 가질 수있는 “들쭉날쭉 한”배열을 할당하려는 경우와 같이 단편적인 할당 방법이 선호되는 경우가 있습니다. 그러나 일반적으로 이것이 더 나은 방법입니다.
1. 배열 은 포인터 가 아니라는 점을 기억하십시오. 대신 배열 표현식 은 필요에 따라 포인터 표현식으로 변환됩니다.