Las otras respuestas son correctas, pero ninguna de ellas enfatiza la idea de que es posible que las tres contengan el mismo valor , por lo que están de alguna manera incompletas.
La razón por la que esto no se puede entender a partir de las otras respuestas es que todas las ilustraciones, si bien son útiles y definitivamente razonables en la mayoría de las circunstancias, no cubren la situación en la que el puntero se x
señala a sí mismo.
Esto es bastante fácil de construir, pero claramente un poco más difícil de entender. En el siguiente programa, veremos cómo podemos forzar que los tres valores sean idénticos.
NOTA: El comportamiento en este programa no está definido, pero lo estoy publicando aquí simplemente como una demostración interesante de algo que los punteros pueden hacer, pero no deberían .
#include <stdio.h>
int main () {
int *(*x)[5];
x = (int *(*)[5]) &x;
printf("%p\n", x[0]);
printf("%p\n", x[0][0]);
printf("%p\n", x[0][0][0]);
}
Esto se compila sin advertencias tanto en C89 como en C99, y el resultado es el siguiente:
$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c
Curiosamente, los tres valores son idénticos. ¡Pero esto no debería ser una sorpresa! Primero, analicemos el programa.
Declaramos x
como un puntero a una matriz de 5 elementos donde cada elemento es de tipo puntero a int. Esta declaración asigna 4 bytes en la pila de tiempo de ejecución (o más, dependiendo de su implementación; en mi máquina, los punteros son 4 bytes), por lo que x
se refiere a una ubicación de memoria real. En la familia de lenguajes C, los contenidos x
son solo basura, algo que queda del uso anterior de la ubicación, por x
lo que no apunta a ninguna parte, ciertamente no al espacio asignado.
Entonces, naturalmente, podemos tomar la dirección de la variable x
y ponerla en algún lugar, así que eso es exactamente lo que hacemos. Pero seguiremos adelante y lo pondremos en x. Dado que &x
tiene un tipo diferente dex
, necesitamos hacer un reparto para que no recibamos advertencias.
El modelo de memoria se vería así:
0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+
Por lo tanto, el bloque de memoria de 4 bytes en la dirección 0xbfd9198c
contiene el patrón de bits correspondiente al valor hexadecimal 0xbfd9198c
. Suficientemente simple.
A continuación, imprimimos los tres valores. Las otras respuestas explican a qué se refiere cada expresión, por lo que la relación debería ser clara ahora.
Podemos ver que los valores son los mismos, pero solo en un sentido de nivel muy bajo ... sus patrones de bits son idénticos, pero los datos de tipo asociados con cada expresión significan que sus valores interpretados son diferentes. Por ejemplo, si imprimimos x[0][0][0]
usando la cadena de formato%d
, obtendríamos un número negativo enorme, por lo que los "valores" son, en la práctica, diferentes, pero el patrón de bits es el mismo.
Esto es realmente simple ... en los diagramas, las flechas solo apuntan a la misma dirección de memoria en lugar de a diferentes direcciones. Sin embargo, aunque pudimos forzar un resultado esperado de un comportamiento indefinido, es solo eso: indefinido. Este no es un código de producción, sino simplemente una demostración en aras de la integridad.
En una situación razonable, usará malloc
para crear la matriz de 5 punteros int, y nuevamente para crear las entradas que se apuntan en esa matriz.malloc
siempre devuelve una dirección única (a menos que no tenga memoria, en cuyo caso devuelve NULL o 0), por lo que nunca tendrá que preocuparse por punteros autorreferenciales como este.
Esperemos que esa sea la respuesta completa que estás buscando. No debe esperar x[0]
, x[0][0]
y x[0][0][0]
ser igual, pero podrían serlo si se lo obliga. Si algo te pasó por la cabeza, ¡avísame para que te lo aclare!
x[0]
,x[0][0]
yx[0][0][0]
tienen diferentes tipos. No se pueden comparar. ¿Qué quieres decir con!=
?