要了解这种技巧,首先需要了解指针的区别,即,减去两个指向同一数组元素的指针时会发生什么?
当一个指针与另一个指针相减时,结果就是指针之间的距离(以数组元素为单位)。因此,如果p指向a[i]并q指向a[j],则p - q等于i - j。
C11:6.5.6加法运算符(p9):
当减去两个指针时,两个指针都将指向同一数组对象的元素,或者指向数组对象的最后一个元素;结果是两个数组元素的下标不同。[...]。
换句话说,如果表达式P和Q分别指向数组对象的i-th和j-th元素,则表达式(P)-(Q)具有值,i−j只要该值适合于type对象ptrdiff_t。
现在,我希望您知道将数组名转换为指针,a并将其转换为指向array的第一个元素的指针a。&a是整个内存块的地址,即它是array的地址a。下图将帮助您理解(请阅读此答案以获取详细说明):

这将帮助您理解第 i 个数组的原因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):
当减去两个指针时,两个指针均应指向同一数组对象的元素,或者指向数组对象的最后一个元素;结果是两个数组元素的下标不同。结果的大小是实现定义的,并且其类型(有符号整数类型)ptrdiff_t在<stddef.h>标头中定义。如果结果无法在该类型的对象中表示,则该行为未定义。
由于(&a)[n]既不指向同一数组对象的元素,也不指向数组对象的最后一个元素,因此(&a)[n] - a都不会调用未定义的行为。
另请注意,最好将函数的返回类型更改p为ptrdiff_t。