이 해킹을 이해하려면 먼저 포인터 차이를 이해해야합니다. 즉, 동일한 배열의 요소를 가리키는 두 포인터 를 빼면 어떻게됩니까?
한 포인터를 다른 포인터에서 빼면 결과는 포인터 간의 거리 (배열 요소로 측정)입니다. 그래서, 경우 p
에 점 a[i]
과 q
점하기 위해 a[j]
, 다음 p - q
과 같다i - j
.
C11 : 6.5.6 가산 연산자 (p9) :
두 개의 포인터를 빼면 둘 다 같은 배열 객체의 요소 또는 배열 객체의 마지막 요소를 지나는 요소를 가리켜 야합니다. 결과는 두 배열 요소의 아래 첨자의 차이입니다 . [...].
즉, 식 경우 P
와 Q
포인트 각각 i
번째 및 j
배열 객체의 번째 요소 식은 (P)-(Q)
값 갖는i−j
유형의 객체에 맞는 값을 제공 ptrdiff_t
.
이제 배열 이름을 포인터로 a
변환하고 포인터를 배열의 첫 번째 요소로 변환하는 것을 알고 a
있습니다. &a
는 전체 메모리 블록의 주소입니다 a
. 즉, 배열의 주소입니다 . 아래 그림은 이해하는 데 도움이됩니다 ( 자세한 설명은 이 답변 을 읽으십시오 ).
이렇게하면 왜 a
, 왜 &a
같은 주소를 가지고 있고 (&a)[i]
i 번째 배열 의 주소가 어떻게 주소와 같은지 이해하는 데 도움이됩니다 a
.
그래서, 진술
return (&a)[n] - a;
에 해당
return (&a)[n] - (&a)[0];
이 차이는 포인터 (&a)[n]
와 사이의 요소 수를 제공하며 각 요소 (&a)[0]
는 n
배열입니다 n
int
. 따라서 총 배열 요소는 n*n
= n
2 입니다.
노트:
C11 : 6.5.6 가산 연산자 (p9) :
두 개의 포인터를 빼면 둘 다 같은 배열 객체의 요소를 가리 키거나 하나는 배열 객체의 마지막 요소를 지나야합니다 . 결과는 두 배열 요소의 아래 첨자의 차이입니다. 결과의 크기는 implementation-defined 이며 해당 유형 (부호있는 정수 유형)이 헤더에 ptrdiff_t
정의됩니다 <stddef.h>
. 해당 유형의 객체에서 결과를 표현할 수없는 경우 동작이 정의되지 않습니다.
이후 (&a)[n]
어레이 오브젝트의 마지막 요소 과거 동일한 배열 오브젝트 나 하나의 요소도 포인트 (&a)[n] - a
호출한다 정의되지 않은 동작 .
또한 함수의 반환 형식을 변경하는 것이 더 나은, 그주의 p
에 ptrdiff_t
.