Me preguntaron cuál es el resultado del siguiente código:
int a[5] = { 1, 3, 5, 7, 9 }; int *p = (int *)(&a + 1); printf("%d, %d", *(a + 1), *(p - 1));3, 93, 12, 1La respuesta es NO.1
Es fácil obtener *(a+1) es 3.
Pero, ¿qué int *p = (int *)(&a + 1); y *(p - 1) ?
Esta:
&a + 1; está tomando la dirección de a , una matriz, y sumando 1, que suma el tamaño de una a , es decir, 5 enteros. Luego, la indexación "retrocede", un número entero, que termina en el elemento final de a archivo .
Normalmente, siempre que se utilizan matrices en expresiones, se "descomponen" en un puntero al primer elemento. Hay algunas excepciones a esta regla y una de ellas es el operador & .
&a por lo tanto produce un puntero a la matriz de tipo int (*)[5] . Entonces &a + 1 es aritmética de punteros en dicho tipo, lo que significa que la dirección del puntero aumenta en el tamaño de un int [5] . Terminamos apuntando justo más allá de la matriz, pero C en realidad nos permite hacerlo siempre que no eliminemos la referencia a esa ubicación.
Luego, el puntero es forzado a una conversión de tipo a (int *) que también podemos hacer: C permite prácticamente cualquier tipo de conversión de puntero salvaje siempre que no eliminemos la referencia o provoquemos una desalineación, etc.
p - 1 hace aritmética de punteros en el tipo int y el tipo real de datos en la matriz también es int , por lo que podemos eliminar la referencia a esa ubicación. Terminamos en el último elemento de la matriz.
En la linea
int *p = (int *)(&a + 1);
tenga en cuenta que se está escribiendo &a , no a . Esto es importante.
Si simplemente se hubiera escrito a , entonces la matriz se habría reducido a un puntero al primer elemento, es decir, a &a[0] . Sin embargo, dado que en su lugar se usó la expresión &a , el resultado de esta expresión tiene el mismo valor que si se hubiera usado a o &a[0] , pero el tipo es diferente: el tipo es un puntero a una matriz de 5 elementos int , en lugar de un puntero a un solo elemento int .
De acuerdo con las reglas de la aritmética de punteros, incrementar un puntero en 1 aumentará la dirección de memoria en el tamaño del objeto al que apunta. Dado que el puntero no apunta a un solo elemento, sino a una matriz de 5 elementos, la dirección de memoria se incrementará en 5 * sizeof(int) . Por lo tanto, después de incrementar el puntero, el valor (pero no el tipo) del puntero será equivalente a &a[5] , es decir, uno más allá del final de la matriz.
Después de lanzar este puntero a int * y asignar el resultado a p , la expresión p es totalmente equivalente a &a[5] (tanto en valor como en tipo).
Por lo tanto, la expresión *(p - 1) es equivalente a *(&a[5] - 1) , que es equivalente a *(&a[4]) , o simplemente a[4] .