with - Não é possível entender isso para calcular o quadrado de um número




declare array size with variable c++ (4)

Obviamente, um hack ... mas uma maneira de enquadrar um número sem usar o operador * (esse era um requisito de um concurso de codificação).

(&a)[n] 

é equivalente a um ponteiro para int no local

(a + sizeof(a[n])*n)

e assim toda a expressão é

  (&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

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 pergunta é: como isso acontece? Após um pequeno teste, descobri que entre (&a)[k] e (&a)[k+1] é sizeof(a) / sizeof(int) . Por que é que?


Para entender esse truque, primeiro você precisa entender a diferença do ponteiro, ou seja, o que acontece quando dois ponteiros apontando para elementos do mesmo array são subtraídos?

Quando um ponteiro é subtraído de outro, o resultado é a distância (medida em elementos de matriz) entre os ponteiros. Então, se p aponta para a[i] e q aponta para a[j] , então p - q é igual a i - j .

C11: 6.5.6 Operadores aditivos (p9):

Quando dois ponteiros são subtraídos , ambos devem apontar 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 apontam para, respectivamente, os elementos i th e j -th de um objeto array, a expressão (P)-(Q) tem o valor i−j desde que o valor caiba em um objeto do tipo ptrdiff_t .

Agora estou esperando que você esteja ciente da conversão do nome da matriz para o ponteiro, a converte para o ponteiro para o primeiro elemento da matriz a . &a é o endereço de todo o bloco de memória, ou seja, é um endereço da matriz a . A figura abaixo irá ajudá-lo a entender ( leia esta resposta para uma explicação detalhada ):

Isso ajudará você a entender por que a e &a tem o mesmo endereço e como (&a)[i] é o endereço do i th array (do mesmo tamanho que o de a ).

Então, a afirmação

return (&a)[n] - a; 

é equivalente a

return (&a)[n] - (&a)[0];  

e esta diferença dará o número de elementos entre os ponteiros (&a)[n] e (&a)[0] , que são n arrays de cada n int elementos. Portanto, os elementos totais da matriz são n*n = n 2 .

NOTA:

C11: 6.5.6 Operadores aditivos (p9):

Quando dois ponteiros são subtraídos, ambos devem apontar 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 cabeçalho <stddef.h> . Se o resultado não puder ser representado em um objeto desse tipo, o comportamento será indefinido.

Uma vez que (&a)[n] não aponta para elementos do mesmo objeto de matriz nem um passado do último elemento do objeto de matriz, (&a)[n] - a invocará comportamento indefinido .

Note também que, melhor mudar o tipo de retorno da função p para ptrdiff_t .


a é uma matriz (variável) de n int .

&a é um ponteiro para um array (variável) de n int .

(&a)[1] é um ponteiro de int int após o último elemento da matriz. Este ponteiro é n int elementos depois de &a[0] .

(&a)[2] é um ponteiro de int int passado após o último elemento da matriz de duas matrizes. Este ponteiro é 2 * n int elementos depois de &a[0] .

(&a)[n] é um ponteiro de int int após o último elemento da matriz de n arrays. Este ponteiro é n * n int depois de &a[0] . Apenas subtraia &a[0] ou a e você tem n .

É claro que este é um comportamento tecnicamente indefinido, mesmo que funcione em sua máquina como (&a)[n] não aponta dentro da matriz ou após o último elemento da matriz (conforme requerido pelas regras C da aritmética de ponteiros).


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

Portanto,

  1. tipo de (&a)[n] é int[n] ponteiro
  2. tipo de a ponteiro int

Agora a expressão (&a)[n]-a executa uma subtração de ponteiro:

  (&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




variable-length-array