He encontrado una función que calcula el cuadrado de un número:
int p(int n) {
int a[n]; //works on C99 and above
return (&a)[n] - a;
}
Devuelve el valor de n 2 . La pregunta es, ¿cómo hace eso? Después de una pequeña prueba, encontré que entre (&a)[k]
y (&a)[k+1]
es sizeof(a)
/ sizeof(int)
. ¿Porqué es eso?
int p(n)
? ¿Eso incluso compila?int q(int n) { return sizeof (char [n][n]); }
sizeof
fue para guardar caracteres. Todos los demás: este es un código intencionalmente oscuro, es un comportamiento indefinido, la respuesta de @ ouah es correcta.Respuestas:
Obviamente, un truco ... pero una forma de cuadrar un número sin usar el
*
operador (este era un requisito del concurso de codificación).es equivalente a un puntero a la
int
ubicacióny así toda la expresión es
fuente
(&a)
como un puntero a un objeto den*sizeof(int)
cuandon
no se conoce en el momento de la compilación. C solía ser un lenguaje simple ...Para comprender este truco, primero debe comprender la diferencia del puntero, es decir, ¿qué sucede cuando se restan dos punteros que apuntan a elementos de la misma matriz ?
Cuando se sustrae un puntero de otro, el resultado es la distancia (medida en elementos de la matriz) entre los punteros. Entonces, si
p
apuntaa[i]
yq
apuntaa[j]
, entoncesp - q
es igual ai - j
.C11: 6.5.6 Operadores aditivos (p9):
Ahora espero que esté al tanto de la conversión del nombre de la matriz a puntero, se
a
convierte en puntero al primer elemento de la matriza
.&a
es la dirección de todo el bloque de memoria, es decir, es una dirección de matriza
. La siguiente figura lo ayudará a comprender ( lea esta respuesta para obtener una explicación detallada ):Esto le ayudará a comprender por qué
a
y&a
tiene la misma dirección y cómo(&a)[i]
es la dirección de la matriz (del mismo tamaño que la dea
).Entonces, la declaración
es equivalente a
y esta diferencia dará el número de elementos entre los punteros
(&a)[n]
y(&a)[0]
, que sonn
matrices de cada uno de losn
int
elementos. Por lo tanto, los elementos de la matriz total sonn*n
=n
2 .NOTA:
C11: 6.5.6 Operadores aditivos (p9):
Dado que
(&a)[n]
ni apunta a elementos del mismo objeto de matriz ni a uno más allá del último elemento del objeto de matriz,(&a)[n] - a
invocará un comportamiento indefinido .También tenga en cuenta que es mejor cambiar el tipo de función de retorno
p
aptrdiff_t
.fuente
&a[k]
es una dirección delk
elemento de matriza
. Es(&a)[k]
que siempre se considerará una dirección de una matriz dek
elementos. Entonces, el primer elemento está en la posicióna
(o&a
), el segundo está en la posicióna
+ (número de elementos de la matriza
que esn
) * (tamaño de un elemento de la matriz) y así sucesivamente. Y tenga en cuenta que, la memoria para matrices de longitud variable se asigna en la pila, no en el montón.a
es una matriz (variable) den
int
.&a
es un puntero a una matriz (variable) den
int
.(&a)[1]
es un puntero deint
unoint
pasado el último elemento de la matriz. Este puntero esn
int
elementos después&a[0]
.(&a)[2]
es un puntero deint
unint
pasado el último elemento de matriz de dos matrices. Este puntero es2 * n
int
elementos después&a[0]
.(&a)[n]
es un puntero deint
unoint
pasado el último elemento den
matriz de matrices. Este puntero esn * n
int
elementos después&a[0]
. Solo resta&a[0]
oa
y tienesn
.Por supuesto, este es un comportamiento técnicamente indefinido, incluso si funciona en su máquina, ya
(&a)[n]
que no apunta dentro de la matriz o más allá del último elemento de la matriz (como lo requieren las reglas C de la aritmética del puntero).fuente
[n]
sintaxis declara una matriz y las matrices se descomponen en punteros. Tres cosas útiles por separado con esta consecuencia.(&a)[n]
es tipoint[n]
, y que se expresa comoint*
debido a las matrices que se expresan como la dirección de su primer elemento, en caso de que no esté claro en la descripción.Si tiene dos punteros que apuntan a dos elementos de la misma matriz, entonces su diferencia producirá el número de elementos entre estos punteros. Por ejemplo, este fragmento de código generará 2.
Ahora consideremos la expresión
En esta expresión
a
tiene tipoint *
y apunta a su primer elemento.La expresión
&a
tiene tipoint ( * )[n]
y apunta a la primera fila de la matriz bidimensional con imagen. Su valor coincide con el valor de losa
tipos aunque son diferentes.es el enésimo elemento de esta matriz bidimensional con imagen y tiene el tipo
int[n]
Es decir, es la enésima fila de la matriz con imagen. En expresión(&a)[n] - a
, se convierte a la dirección de su primer elemento y tiene el tipo `int *.Entonces, entre
(&a)[n]
ya
hay n filas de n elementos. Entonces la diferencia será igual an * n
.fuente
Así,
(&a)[n]
esint[n]
punteroa
esint
punteroAhora la expresión
(&a)[n]-a
realiza una sustracción de puntero:fuente