Programing

이 방법으로 숫자의 제곱을 계산할 수 없습니다

crosscheck 2020. 6. 25. 08:14
반응형

이 방법으로 숫자의 제곱을 계산할 수 없습니다


숫자의 제곱을 계산하는 함수를 찾았습니다.

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) :

두 개의 포인터를 빼면 둘 다 같은 배열 객체의 요소 또는 배열 객체의 마지막 요소를 지나는 요소를 가리켜 야합니다. 결과는 두 배열 요소의 아래 첨자의 차이입니다 . [...].
즉, 식 경우 PQ포인트 각각 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= n2 입니다.


노트:

C11 : 6.5.6 가산 연산자 (p9) :

두 개의 포인터를 빼면 둘 다 같은 배열 객체의 요소를 가리 키거나 하나는 배열 객체의 마지막 요소를 지나야합니다 . 결과는 두 배열 요소의 아래 첨자의 차이입니다. 결과의 크기는 implementation-defined 이며 해당 유형 (부호있는 정수 유형)이 헤더에 ptrdiff_t정의됩니다 <stddef.h>. 해당 유형의 객체에서 결과를 표현할 수없는 경우 동작이 정의되지 않습니다.

이후 (&a)[n]어레이 오브젝트의 마지막 요소 과거 동일한 배열 오브젝트 나 하나의 요소도 포인트 (&a)[n] - a호출한다 정의되지 않은 동작 .

또한 함수의 반환 형식을 변경하는 것이 더 나은, 그주의 pptrdiff_t.


a의 (변수) 배열입니다 n int.

&a의 (변수) 배열에 대한 포인터입니다 n int.

(&a)[1]의 포인터 intint마지막 배열 요소 과거. 이 포인터는 n int이후의 요소 &a[0]입니다.

(&a)[2]의 포인터를 intint두 배열의 마지막 배열 요소 과거. 이 포인터는 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,

  1. type of (&a)[n] is int[n] pointer
  2. type of a is int 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

참고URL : https://stackoverflow.com/questions/27828822/cant-understand-this-way-to-calculate-the-square-of-a-number

반응형