このハックを理解するには、最初にポインターの違いを理解する必要があります。つまり、同じ配列の要素を指す2つのポインターを減算するとどうなるでしょうか。
1つのポインターが別のポインターから差し引かれると、結果はポインター間の距離(配列要素で測定)になります。したがって、をp指すとa[i]をq指す場合a[j]、はとp - q等しくなりi - jます。
C11:6.5.6加算演算子(p9):
2つのポインターが減算されると、両方が同じ配列オブジェクトの要素を指すか、配列オブジェクトの最後の要素の1 つ後を指します。結果は、2つの配列要素の添え字の差です。[...]。
換言すれば、式場合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= n2です。
注意:
C11:6.5.6加算演算子(p9):
2つのポインターが差し引かれると、両方とも同じ配列オブジェクトの要素を指すか、配列オブジェクトの最後の要素の1つ前を指します。結果は、2つの配列要素の添え字の差です。結果のサイズは実装定義であり、その型(符号付き整数型)はヘッダーでptrdiff_t定義され<stddef.h>ます。結果がそのタイプのオブジェクトで表現できない場合、動作は未定義です。
(&a)[n]同じ配列オブジェクトの要素も、配列オブジェクトの最後の要素の1つ後もポイントしないため、未定義の動作(&a)[n] - aを呼び出します。
また、関数の戻り値の型をに変更することをお勧めpしptrdiff_tます。