confuso en puntero y matriz

Tenemos

int a[5]={10, 20, 30, 40, 50}; 

Me gustaría saber cómo funcionan los siguientes dos segmentos de código.

  int *ptr = (int *)(&a+1); int *t = (int *)(&a -1); 

Si tenemos

  printf("%d %d %d \n", *(a+1), *(ptr-1), *(t+1)); 

¿Cuál debería ser el resultado?

Todos los problemas provienen del uso de &a , que es un puntero a “una matriz de cinco enteros”, de modo que la aritmética de punteros (cuando piensas en términos de direcciones) se “escala” por tamaño de sizeof(a) (que podría ser, por ejemplo, 20 si los int son de 4 bytes y el comstackdor no necesita relleno para propósitos de alineación, hipótesis razonables, aunque, por supuesto, lejos de ser ciertas.

Así que después

 int *ptr = (int *)(&a+1); int *t = (int *)(&a -1); 

ptr es un puntero a int en la dirección de memoria “sizeof (a) más que la dirección a”, y t manera similar para “sizeof (a) menor que la dirección de a”. Por lo tanto…:

  printf("%d %d %d \n", *(a+1), *(ptr-1), *(t+1)); 

¿Cuál debería ser el resultado?

Posiblemente sea una violación de segmentación, de lo contrario 20 seguido de dos valores enteros completamente arbitrarios. Dado que ptr y t son punteros a int , la escala aritmética de direcciones para su -1 y +1 no compensa el hecho en &a (la escala en términos de direcciones de memoria es por sizeof(int) , no sizeof(a) !), así que ptr-1 y t+1 están apuntando a (supuestos 😉 int s que son respectivamente “unos pocos int s después del final de a ” y “unos pocos int s antes del comienzo de a “.

No hay forma de saber si en esas direcciones arbitrarias hay alguna memoria que el proceso pueda abordar (de ahí la posibilidad de violaciones de segmentación), y, si hay alguna memoria accesible, lo que su contenido “visto como un int ” podría posiblemente ser.

Edición : @caf señala que ptr - 1 no es inválido – apunta correctamente al último elemento de a ; así que la salida (a menos que haya una falla de segmentación, que @NullUserException cree que es muy improbable, pero en este punto no estamos de acuerdo 😉 comenzaría con 20 50 antes de la tercera, “arbitraria” basura. El punto es, según el estándar de C, es válido calcular (aunque no usar) el puntero “solo una pasada el final” de una matriz, y el tamaño de una matriz debe ser exactamente la longitud de la matriz, el tamaño de sus elementos (relleno está permitido para el tipo de un elemento, si es necesario, y si es así, se muestra en el tamaño propio del elemento, pero no para la matriz en su conjunto). Sutil, pero importante ;-).

Dado que el tipo de a es array-of-5- int s , eso significa que el tipo de &a es puntero a array-of-5- int s .

Cuando agrega o resta 1 de un puntero, le pide que apunte al objeto siguiente o anterior de ese tipo en la memoria. Así que &a+1 está creando un puntero a la matriz de 5- int inmediatamente después de a en memoria (que no existe), y &a-1 crea un puntero a la matriz de 5- int inmediatamente antes de a en la memoria (que tampoco existe). En la memoria, se ve así (donde cada celda representa un int ):

 Address: &a-1 &a &a+1 Contents: | ? | ? | ? | ? | ? | 10 | 20 | 30 | 40 | 50 | ? | ? | ? | ? | ? | 

Cuando se usa a en la expresión *(a+1) , se convierte en un puntero a su primer elemento, por lo que un puntero a int señala al valor 10 . Al agregarle uno, el puntero señala a la siguiente int : a+1 puntos en el valor 20 . *(a+1) luego recupera ese valor, por lo que el primer número impreso es 20.

Como ptr es también un puntero a int , eso significa que ptr - 1 crea un puntero al int inmediatamente antes de ptr ; en este caso, ptr a los 50. Por lo tanto, el segundo número impreso es 50.

De manera similar, t + 1 crea un puntero al int inmediatamente después de t : en este caso, ¿es el segundo ? En el diagtwig de arriba. Este es un valor sin inicializar: puede imprimir cualquier cosa, o incluso bloquear el progtwig.

 Address: &a-1 &a &a+1 t t+1 a a+1 ptr-1 ptr Contents: | ? | ? | ? | ? | ? | 10 | 20 | 30 | 40 | 50 | ? | ? | ? | ? | ? | 

“¿Cuál debería ser el resultado”?

La próxima vez que quiera saber qué debería hacer un pequeño fragmento de código como este, consulte esto: http://ideone.com/4fCud

El resultado que obtuve de eso fue:

20 50 134520820

Editar:

Cuando ejecuta un progtwig, vea una salida como esta y pregúntese, “¿de dónde vino ese valor?” Es posible que se haya encontrado con un comportamiento indefinido.

En este caso, el tercer valor no apunta a donde podría pensar que apuntaría. Es leer memoria no inicializada (lo más probable), memoria que pertenece al código que se encuentra en su espacio de proceso, pero fuera de su progtwig (una biblioteca que cargó, o el tiempo de ejecución de C), o memoria que simplemente no tiene nada que ver con este progtwig (menos probable, debido a la memoria protegida).

Vamos a verlo pieza por pieza.

&a significa la dirección de a. Por lo tanto, obtiene la dirección de la dirección del entero 10.
&a+1 es el siguiente puntero sobre eso. Así que es la cosa almacenada después de la variable a en la memoria. Mala idea.
&a-1 es la cosa almacenada antes de en memoria. Una vez más, mala idea.

*(a+1) es la cosa en la ubicación señalada por a, más un entero. Eso sería a[1] , o 20.
*(ptr-1) es a , porque ptr es &a+1 , entonces ptr-1 es &a . Es el valor del indicador de a . Imprimirlo como %d es un error. Si dijeras **(ptr-1) , obtendrías un 10 más significativo del printf .
*(t+1) también es a , según lo anterior pero con las ventajas y desventajas cambiadas.