无法理解这种方式来计算一个数字的平方

我find了一个函数来计算一个数字的平方:

int p(int n) { int a[n]; //works on C99 and above return (&a)[n] - a; } 

它返回n 2的值。 问题是,它是如何做到的? 经过一些testing,我发现(&a)[k](&a)[k+1]sizeof(a) / sizeof(int) 。 这是为什么?

显然是一个黑客…而是一个不使用*运算符的方法(这是一个编码竞赛要求)。

 (&a)[n] 

相当于一个指向int的指针

 (a + sizeof(a[n])*n) 

因此整个expression是

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

当减去两个指针时 ,都应指向同一个数组对象的元素,或指向数组对象的最后一个元素的元素; 结果是两个数组元素的下标差异 。 […]。
换句话说,如果expression式PQ分别指向数组对象的第i个和第j个元素, 则expression式(P)-(Q)具有值i−j只要该值适合于ptrdiff_ttypes的对象。

现在我期待着你知道数组名称转换为指针, 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数组。 因此,总arrays元素是n*n = n 2


注意:

C11:6.5.6附加操作符(p9):

当减去两个指针时, 都应指向同一个数组对象的元素,或指向数组对象的最后一个元素的元素 ; 结果是两个数组元素的下标差异。 结果的大小是实现定义的 ,其types(有符号整数types)是在<stddef.h>头文件中定义的ptrdiff_t 。 如果结果在该types的对象中不可表示,则行为是未定义的。

由于(&a)[n]既不指向相同数组对象的元素也不指向数组对象的最后一个元素, (&a)[n] - a将调用未定义的行为

还要注意,最好将函数p的返回types更改为ptrdiff_t

an int的(可变)数组。

&a是一个指向n int )的(variables)数组的指针。

(&a)[1]是最后一个数组元素之后的int int指针。 这个指针是&a[0]之后的n int元素。

(&a)[2]是两个数组中最后一个数组元素的int指针。 这个指针是&a[0]之后的2 * n int元素。

(&a)[n]n数组中最后一个数组元素的int指针。 该指针是&a[0]之后的n * n int元素。 只需要减去&a[0]或者你有n

当然这在技术上是未定义的行为,即使它在你的机器上工作,因为(&a)[n]不指向数组内部或指向最后一个数组元素(如指针算术C规则所要求的)。

如果你有两个指向同一个数组的两个元素的指针,那么它的差异将会产生这些指针之间的元素数。 例如,这段代码将输出2。

 int a[10]; int *p1 = &a[1]; int *p2 = &a[3]; printf( "%d\n", p2 - p1 ); 

现在让我们考虑expression

 (&a)[n] - a; 

在这个expression式中, atypes是int *并指向它的第一个元素。

expression式&atypes为int ( * )[n]并指向映像二维数组的第一行。 它的值匹配a虽然types不同的值。

 ( &a )[n] 

是这个成像的二维数组的第n个元素,并且具有typesint[n]即它是成像数组的第n行。 在expression式(&a)[n] - a它被转换为它的第一个元素的地址并且具有types“int *”。

所以在(&a)[n]和n行之间有n个元素。 所以差异将等于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 

从而,

  1. (&a)[n]int[n]指针
  2. a的types是int指针

现在expression式(&a)[n]-a执行指针减法:

  (&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