Para entender esse hack, primeiro você precisa entender a diferença de ponteiro, ou seja, o que acontece quando dois ponteiros apontando para elementos da mesma matriz são subtraídos?
Quando um ponteiro é subtraído de outro, o resultado é a distância (medida em elementos da matriz) entre os ponteiros. Então, se p
aponta para a[i]
e q
aponta para a[j]
, então p - q
é igual ai - j
.
C11: 6.5.6 Operadores aditivos (p9):
Quando dois ponteiros são subtraídos , ambos apontam para elementos do mesmo objeto de matriz ou um após o último elemento do objeto de matriz; o resultado é a diferença dos subscritos dos dois elementos da matriz . [...]
Em outras palavras, se as expressões P
e Q
apontarem para, respectivamente, os elementos -ésimo i
-ésimo j
-ésimo de um objeto de matriz, a expressão (P)-(Q)
terá o valori−j
desde que o valor se ajuste a um objeto do tipo ptrdiff_t
.
Agora, espero que você esteja ciente da conversão do nome da matriz em ponteiro, a
converta em ponteiro no primeiro elemento da matriz a
. &a
é o endereço de todo o bloco de memória, ou seja, é um endereço do array a
. A figura abaixo ajudará você a entender ( leia esta resposta para obter explicações detalhadas ):
Isso ajudará você a entender que por isso a
e &a
tem o mesmo endereço e como (&a)[i]
é o endereço do i th array (de mesmo tamanho que a do a
).
Então, a afirmação
return (&a)[n] - a;
é equivalente a
return (&a)[n] - (&a)[0];
e essa diferença fornecerá o número de elementos entre os ponteiros (&a)[n]
e (&a)[0]
, que são n
matrizes cada um dos n
int
elementos. Portanto, o total de elementos da matriz é n*n
= n
2 .
NOTA:
C11: 6.5.6 Operadores aditivos (p9):
Quando dois ponteiros são subtraídos, ambos apontam para elementos do mesmo objeto de matriz ou um após o último elemento do objeto de matriz ; o resultado é a diferença dos subscritos dos dois elementos da matriz. O tamanho do resultado é definido pela implementação e seu tipo (um tipo inteiro assinado) é ptrdiff_t
definido no <stddef.h>
cabeçalho. Se o resultado não for representável em um objeto desse tipo, o comportamento será indefinido.
Como (&a)[n]
nem pontos para elementos do mesmo objeto de matriz nem um após o último elemento do objeto de matriz, (&a)[n] - a
invocará um comportamento indefinido .
Observe também que é melhor alterar o tipo de retorno da função p
para ptrdiff_t
.