Eu encontrei uma função que calcula o quadrado de um número:
int p(int n) {
int a[n]; //works on C99 and above
return (&a)[n] - a;
}
Retorna o valor de n 2 . A questão é: como isso acontece? Após um pequeno teste, descobri que entre (&a)[k]
e (&a)[k+1]
é sizeof(a)
/ sizeof(int)
. Por que é que?
int p(n)
? Isso compila mesmo?int q(int n) { return sizeof (char [n][n]); }
sizeof
foi para salvar caracteres. Todos os outros: este é um código intencionalmente obscuro, é um comportamento indefinido, a resposta de @ ouah está correta.Respostas:
Obviamente, um hack ... mas uma maneira de quadrilhar um número sem usar o
*
operador (este era um requisito de concurso de codificação).é equivalente a um ponteiro para
int
no locale assim toda a expressão é
fonte
(&a)
como um ponteiro para um objeto den*sizeof(int)
quandon
não é conhecido em tempo de compilação. C costumava ser uma simples linguagem ...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 paraa[i]
eq
aponta paraa[j]
, entãop - q
é igual ai - j
.C11: 6.5.6 Operadores aditivos (p9):
Agora, espero que você esteja ciente da conversão do nome da matriz em ponteiro,
a
converta em ponteiro no primeiro elemento da matriza
.&a
é o endereço de todo o bloco de memória, ou seja, é um endereço do arraya
. 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 doa
).Então, a afirmação
é equivalente a
e essa diferença fornecerá o número de elementos entre os ponteiros
(&a)[n]
e(&a)[0]
, que sãon
matrizes cada um dosn
int
elementos. Portanto, o total de elementos da matriz én*n
=n
2 .NOTA:
C11: 6.5.6 Operadores aditivos (p9):
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
paraptrdiff_t
.fonte
&a[k]
é um endereço dok
th elemento da matriza
. É(&a)[k]
que sempre será considerado o endereço de uma matriz dek
elementos. Assim, em primeiro elemento está na posiçãoa
(ou&a
), segundo está na posiçãoa
+ (número de elementos de matriza
que én
) * (tamanho de um elemento de matriz) e assim por diante. E observe que a memória para matrizes de comprimento variável é alocada na pilha, não na pilha.a
é uma matriz (variável) den
int
.&a
é um ponteiro para uma matriz (variável) den
int
.(&a)[1]
é um ponteiro deint
umint
passado o último elemento da matriz. Este ponteiro én
int
elementos depois&a[0]
.(&a)[2]
é um ponteiro deint
umint
passado o último elemento da matriz de duas matrizes. Este ponteiro é2 * n
int
elementos depois&a[0]
.(&a)[n]
é um ponteiro deint
umint
passado o último elemento da matriz den
matrizes. Este ponteiro én * n
int
elementos depois&a[0]
. Basta subtrair&a[0]
oua
e você temn
.É claro que esse é um comportamento tecnicamente indefinido, mesmo que funcione em sua máquina, pois
(&a)[n]
não aponta para dentro da matriz ou ultrapassa o último elemento da matriz (conforme exigido pelas regras C da aritmética dos ponteiros).fonte
[n]
sintaxe declara uma matriz e as matrizes se decompõem em ponteiros. Três coisas separadamente úteis com essa conseqüência.(&a)[n]
é tipoint[n]
, e que se expressa comoint*
devido às matrizes que exprimem como o endereço do seu primeiro elemento, no caso de que não estava claro na descrição.Se você tiver dois ponteiros que apontam para dois elementos da mesma matriz, sua diferença produzirá o número de elementos entre esses ponteiros. Por exemplo, este trecho de código produzirá 2.
Agora vamos considerar a expressão
Nesta expressão
a
tem tipoint *
e aponta para seu primeiro elemento.A expressão
&a
tem tipoint ( * )[n]
e aponta para a primeira linha da matriz bidimensional da imagem. Seu valor corresponde ao valor dosa
tipos diferentes.é o n-ésimo elemento dessa matriz bidimensional da imagem e tem o tipo
int[n]
Isso é a n-ésima linha da matriz da imagem. Na expressão,(&a)[n] - a
ele é convertido no endereço do seu primeiro elemento e tem o tipo `int *.Portanto, entre
(&a)[n]
ea
existem n linhas de n elementos. Então a diferença será igual an * n
.fonte
Portanto,
(&a)[n]
éint[n]
ponteiroa
éint
ponteiroAgora a expressão
(&a)[n]-a
executa uma subtração de ponteiro:fonte