As outras respostas estão corretas, mas nenhuma delas enfatiza a idéia de que é possível que todas as três contenham o mesmo valor e, portanto, estão incompletas.
A razão pela qual isso não pode ser entendido pelas outras respostas é que todas as ilustrações, embora úteis e definitivamente razoáveis na maioria das circunstâncias, falham em cobrir a situação em que o ponteiro x
aponta para si mesmo.
Isso é muito fácil de construir, mas claramente um pouco mais difícil de entender. No programa abaixo, veremos como podemos forçar todos os três valores a serem idênticos.
NOTA: O comportamento neste programa é indefinido, mas eu o estou postando aqui apenas como uma demonstração interessante de algo que os ponteiros podem fazer, mas não deveriam .
#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]);
}
Isso compila sem avisos em C89 e C99 e a saída é a seguinte:
$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c
Curiosamente, todos os três valores são idênticos. Mas isso não deveria ser uma surpresa! Primeiro, vamos dividir o programa.
Declaramos x
como ponteiro para uma matriz de 5 elementos em que cada elemento é do tipo ponteiro para int. Esta declaração aloca 4 bytes na pilha de tempo de execução (ou mais, dependendo da sua implementação; nos ponteiros da minha máquina são 4 bytes), portanto, x
está se referindo a um local de memória real. Na família C de idiomas, o conteúdo de x
é apenas lixo, algo que resta do uso anterior do local, portanto x
ele não aponta para lugar nenhum - certamente não para o espaço alocado.
Então, naturalmente, podemos pegar o endereço da variável x
e colocá-lo em algum lugar, então é exatamente isso que fazemos. Mas vamos em frente e colocá-lo no próprio x. Como &x
tem um tipo diferente x
, precisamos fazer um elenco para não receber avisos.
O modelo de memória ficaria assim:
0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+
Portanto, o bloco de 4 bytes de memória no endereço 0xbfd9198c
contém o padrão de bits correspondente ao valor hexadecimal 0xbfd9198c
. Simples o suficiente.
Em seguida, imprimimos os três valores. As outras respostas explicam a que cada expressão se refere, então o relacionamento deve ficar claro agora.
Podemos ver que os valores são os mesmos, mas apenas em um nível muito baixo ... seus padrões de bits são idênticos, mas os dados de tipo associados a cada expressão significam que seus valores interpretados são diferentes. Por exemplo, se imprimíssemos x[0][0][0]
usando a string de formato %d
, obteríamos um número negativo enorme; portanto, os "valores" são, na prática, diferentes, mas o padrão de bits é o mesmo.
Isso é realmente muito simples ... nos diagramas, as setas apontam apenas para o mesmo endereço de memória e não para diferentes. No entanto, enquanto conseguimos forçar um resultado esperado a partir de um comportamento indefinido, é exatamente isso - indefinido. Este não é um código de produção, mas simplesmente uma demonstração por uma questão de integridade.
Em uma situação razoável, você usará malloc
para criar a matriz de 5 ponteiros int e novamente para criar as entradas apontadas nessa matriz. malloc
sempre retorna um endereço exclusivo (a menos que você esteja com falta de memória; nesse caso, ele retorna NULL ou 0), para que você nunca precise se preocupar com ponteiros auto-referenciais como este.
Espero que essa seja a resposta completa que você está procurando. Você não deveria esperar x[0]
, x[0][0]
e x[0][0][0]
ser igual, mas eles poderiam ser se forçados. Se alguma coisa passou pela sua cabeça, me avise para que eu possa esclarecer!
x[0]
,x[0][0]
Ex[0][0][0]
ter tipos diferentes. Eles não podem ser comparados. Como assim!=
?