이 방법으로 숫자의 제곱을 계산할 수 없습니다
숫자의 제곱을 계산하는 함수를 찾았습니다.
int p(int n) {
int a[n]; //works on C99 and above
return (&a)[n] - a;
}
n 2의 값을 반환합니다 . 질문은, 어떻게합니까? 약간의 테스트 후, 나는 사이에 발견 (&a)[k]
하고 (&a)[k+1]
있다 sizeof(a)
/ sizeof(int)
. 왜 그런 겁니까?
분명히 해킹 ...하지만 *
연산자 를 사용하지 않고 숫자를 제곱하는 방법입니다 (코딩 컨테스트 요구 사항이었습니다).
(&a)[n]
int
위치를 가리키는 포인터와 같습니다.
(a + sizeof(a[n])*n)
따라서 전체 표현은
(&a)[n] -a
= (a + sizeof(a[n])*n -a) /sizeof(int)
= sizeof(a[n])*n / sizeof(int)
= sizeof(int) * n * n / sizeof(int)
= n * n
이 해킹을 이해하려면 먼저 포인터 차이를 이해해야합니다. 즉, 동일한 배열의 요소를 가리키는 두 포인터 를 빼면 어떻게됩니까?
한 포인터를 다른 포인터에서 빼면 결과는 포인터 사이의 거리 (배열 요소로 측정)입니다. 그래서, 경우 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
.
a
의 (변수) 배열입니다 n
int
.
&a
의 (변수) 배열에 대한 포인터입니다 n
int
.
(&a)[1]
의 포인터 int
일 int
마지막 배열 요소 과거. 이 포인터는 n
int
이후의 요소 &a[0]
입니다.
(&a)[2]
의 포인터를 int
한 int
두 배열의 마지막 배열 요소 과거. 이 포인터는 2 * n
int
이후의 요소 &a[0]
입니다.
(&a)[n]
is a pointer of int
one int
past the last array element of n
arrays. This pointer is n * n
int
elements after &a[0]
. Just subtract &a[0]
or a
and you have n
.
Of course this is technically undefined behavior even if it works on your machine as (&a)[n]
does not point inside the array or one past the last array element (as required by the C rules of pointer arithmetic).
If you have two pointers that point to two elements of the same array then its difference will yield the number of elements between these pointers. For example this code snippet will output 2.
int a[10];
int *p1 = &a[1];
int *p2 = &a[3];
printf( "%d\n", p2 - p1 );
Now let consider expression
(&a)[n] - a;
In this expression a
has type int *
and points to its first element.
Expression &a
has type int ( * )[n]
and points to the first row of imaged two dimensional array. Its value matches the value of a
though types are different.
( &a )[n]
is n-th element of this imaged two dimensional array and has type int[n]
That is it is n-th row of the imaged array. In expression (&a)[n] - a
it is converted to the address of its first element and has type `int *.
So between (&a)[n]
and a
there are n rows of n elements. So the difference will be equal to n * n
.
Expression | Value | Explanation
a | a | point to array of int elements
a[n] | a + n*sizeof(int) | refer to n-th element in array of int elements
-------------------------------------------------------------------------------------------------
&a | a | point to array of (n int elements array)
(&a)[n] | a + n*sizeof(int[n]) | refer to n-th element in array of (n int elements array)
-------------------------------------------------------------------------------------------------
sizeof(int[n]) | n * sizeof(int) | int[n] is a type of n-int-element array
Thus,
- type of
(&a)[n]
isint[n]
pointer - type of
a
isint
pointer
Now the expression (&a)[n]-a
performs a pointer substraction:
(&a)[n]-a
= ((a + n*sizeof(int[n])) - a) / sizeof(int)
= (n * sizeof(int[n])) / sizeof(int)
= (n * n * sizeof(int)) / sizeof(int)
= n * n
'Programing' 카테고리의 다른 글
Bash를 사용하여 마지막 명령의 출력을 변수로 자동 캡처합니까? (0) | 2020.06.25 |
---|---|
실제로 오버로드 된 && 및 || 이유가 있습니까? (0) | 2020.06.25 |
SQL Server 2012 Express 버전의 차이점은 무엇입니까? (0) | 2020.06.25 |
constexpr에서 std :: string을 사용할 수 있습니까? (0) | 2020.06.25 |
데이터베이스에서 django 객체를 다시로드하십시오. (0) | 2020.06.24 |