无法理解这种方式来计算一个数字的平方
我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式P和Q分别指向数组对象的第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 。
a是n 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
从而,
-
(&a)[n]是int[n]指针 - 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