Por que x [0]! = X [0] [0]! = X [0] [0] [0]?

149

Estou estudando um pouco de C ++ e estou brigando com ponteiros. Entendo que posso ter três níveis de ponteiros declarando:

int *(*x)[5];

de modo que *xé um ponteiro para uma matriz de 5 elementos que são ponteiros para int. Também sei disso x[0] = *(x+0);, x[1] = *(x+1)e assim por diante ....

Então, dada a declaração acima, por que x[0] != x[0][0] != x[0][0][0]?

Leo91
fonte
58
x[0], x[0][0]E x[0][0][0]ter tipos diferentes. Eles não podem ser comparados. Como assim !=?
Bolov
4
@celticminstrel eles não são os mesmos: int **x[5]é uma matriz de 5 elementos. Um elemento é um ponteiro para ponteiro para int`
bolov
5
@celticminstrel int** x[5]seria uma matriz de cinco ponteiros que apontam para ponteiros que apontam para int. int *(*x)[5]é um ponteiro para uma matriz de cinco ponteiros que apontam para int.
emlai
5
@celticminstrel regra esquerda-direita , regra spirale , C jargão ↔ Inglês e seu' no seu caminho para se tornar um programador de três estrelas :)
bolov
5
@ Leo91: Primeiramente, você tem dois níveis de indicadores aqui, não três. Em segundo lugar, o que x[0] != x[0][0] != x[0][0][0]significa? Esta não é uma comparação válida em C ++. Mesmo se você o dividir x[0] != x[0][0]e x[0][0] != x[0][0][0]ainda não for válido. Então, o que sua pergunta significa?
AnT

Respostas:

261

xé um ponteiro para uma matriz de 5 ponteiros para int.
x[0]é uma matriz de 5 ponteiros para int.
x[0][0]é um ponteiro para um int.
x[0][0][0]é um int.

                       x[0]
   Pointer to array  +------+                                 x[0][0][0]         
x -----------------> |      |         Pointer to int           +-------+
               0x500 | 0x100| x[0][0]---------------->   0x100 |  10   |
x is a pointer to    |      |                                  +-------+
an array of 5        +------+                        
pointers to int      |      |         Pointer to int                             
               0x504 | 0x222| x[0][1]---------------->   0x222                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x508 | 0x001| x[0][2]---------------->   0x001                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x50C | 0x123| x[0][3]---------------->   0x123                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x510 | 0x000| x[0][4]---------------->   0x000                    
                     |      |                                             
                     +------+                                             

Você pode ver isso

  • x[0]é uma matriz e será convertido em ponteiro para seu primeiro elemento quando usado em uma expressão (com algumas exceções). Portanto x[0], dará o endereço do seu primeiro elemento x[0][0]que é 0x500.
  • x[0][0]contém o endereço de um intque é 0x100.
  • x[0][0][0]contém um intvalor de 10.

Então, x[0]é igual a &x[0][0]e, portanto &x[0][0] != x[0][0],.
Portanto x[0] != x[0][0] != x[0][0][0],.

haccks
fonte
Este diagrama é um pouco confuso para mim: 0x100deve aparecer imediatamente à esquerda da caixa que contém 10, da mesma maneira que 0x500aparece à esquerda da caixa. Em vez de ficar muito à esquerda e abaixo.
7777 MM
@MattMcNabb; Não acho que deva ser confuso, mas muda conforme a sua sugestão para maior clareza.
haccks
4
@haccks - O prazer é meu :) A razão pela qual esse diagrama é ótimo é porque você nem precisa da explicação que deu a seguir. Esse diagrama em si é auto-explicativo, já respondendo à pergunta. O texto a seguir é simplesmente um bônus.
rayryeng
1
Você também pode usar o yed, um software de diagramação. Ele me ajuda muito para organizar meus pensamentos
rpax
@GrijeshChauhan eu uso asciiflow pelos comentários ofthe código, yed para apresentações :)
rpax
133
x[0] != x[0][0] != x[0][0][0]

é, de acordo com seu próprio post,

*(x+0) != *(*(x+0)+0) != *(*(*(x+0)+0)+0)`  

que é simplificado

*x != **x != ***x

Por que deveria ser igual?
O primeiro é o endereço de algum ponteiro.
O segundo é o endereço de outro ponteiro.
E o terceiro é algum intvalor.

deviantfan
fonte
Não consigo entender ... se x [0], x [0] [0], x [0] [0] [0] é equivalente a * (x + 0), * (x + 0 + 0) , * (x + 0 + 0 + 0), por que eles deveriam ter endereços diferentes?
precisa saber é
41
@ Leo91 x[0][0]é (x[0])[0], ou seja *((*(x+0))+0), não *(x+0+0). A desreferência acontece antes do segundo [0].
emlai
4
@ Leo91 x[0][0] != *(x+0+0)assim como x[2][3] != x[3][2].
özg
@ Leo91 O segundo comentário que você "entendeu agora" foi removido. Você não entende alguma coisa (que poderia ser melhor explicada na resposta) ou não é isso que você faz? (algumas pessoas gostam de excluir comentários sem muito conteúdo informativo)
deviantfan
@deviantfan desculpe, eu não consigo entender o que você quer dizer. Compreendo as respostas e muitos comentários que ajudaram a esclarecer o conceito.
precisa saber é
50

Aqui está o layout da memória do seu ponteiro:

   +------------------+
x: | address of array |
   +------------------+
            |
            V
            +-----------+-----------+-----------+-----------+-----------+
            | pointer 0 | pointer 1 | pointer 2 | pointer 3 | pointer 4 |
            +-----------+-----------+-----------+-----------+-----------+
                  |
                  V
                  +--------------+
                  | some integer |
                  +--------------+

x[0]produz "endereço da matriz",
x[0][0]gera "ponteiro 0",
x[0][0][0]produz "algum número inteiro".

Eu acredito que deveria ser óbvio agora, porque eles são todos diferentes.


O exposto acima é suficientemente próximo para o entendimento básico, e é por isso que o escrevi da maneira que o escrevi. No entanto, como hacks apontam corretamente, a primeira linha não é 100% precisa. Então, aqui estão todos os detalhes:

A partir da definição da linguagem C, o valor de x[0]é toda a matriz de ponteiros inteiros. No entanto, matrizes são algo com o qual você realmente não pode fazer nada em C. Você sempre manipula o endereço ou os elementos deles, nunca a matriz inteira como um todo:

  1. Você pode passar x[0]para o sizeofoperador. Mas isso não é realmente um uso do valor, seu resultado depende apenas do tipo.

  2. Você pode tomar seu endereço que produz o valor x, ou seja, "endereço do conjunto" com o tipo int*(*)[5]. Em outras palavras:&x[0] <=> &*(x + 0) <=> (x + 0) <=> x

  3. Em todos os outros contextos , o valor de x[0]decairá em um ponteiro para o primeiro elemento da matriz. Ou seja, um ponteiro com o valor "endereço da matriz" e o tipo int**. O efeito é o mesmo que se você tivesse convertido xpara um ponteiro do tipo int**.

Devido à deterioração do ponteiro de matriz no caso 3., todos os usos de x[0]resultam em um ponteiro que aponta o início da matriz de ponteiros; a chamada printf("%p", x[0])imprimirá o conteúdo das células de memória rotuladas como "endereço da matriz".

cmaster - restabelece monica
fonte
1
x[0]não é o endereço da matriz.
Hackcks #
1
@haccks Sim, seguindo a letra do padrão, x[0]não é o endereço da matriz, é a própria matriz. Eu adicionei uma explicação detalhada sobre isso e por que escrevi que x[0]é o "endereço da matriz". Espero que você goste.
Cmaster - restabelecer monica
gráficos impressionantes que explicam perfeitamente bem!
MK
"No entanto, matrizes são algo com o qual você realmente não pode fazer nada em C." -> Exemplo de contador: printf("%zu\n", sizeof x[0]);informa o tamanho da matriz, não o tamanho de um ponteiro.
chux - Restabelece Monica
@ chux-ReinstateMonica E eu disse: "Você sempre manipula o endereço ou os elementos deles, nunca a matriz inteira como um todo", seguido pelo ponto 1 da enumeração em que falo sobre o efeito de sizeof x[0]...
cmaster - restabelecer monica
18
  • x[0]desreferencia o ponteiro mais externo ( ponteiro para matriz do tamanho 5 do ponteiro para int) e resulta em uma matriz do tamanho 5 do ponteiro para int;
  • x[0][0]desreferencia o ponteiro mais externo e indexa a matriz, resultando em um ponteiro para int;
  • x[0][0][0] desreferencia tudo, resultando em um valor concreto.

A propósito, se você se sentir confuso com o significado desse tipo de declaração, use cdecl .

d125q
fonte
11

Vamos considerar expressões passo a passo x[0], x[0][0]e x[0][0][0].

Como xé definido da seguinte maneira

int *(*x)[5];

expressão em seguida, x[0]é uma matriz do tipo int *[5]. Leve em consideração que expressão x[0]é equivalente a expressão *x. Isso é desreferenciando um ponteiro para uma matriz, obtemos a própria matriz. Vamos denotá-lo como y, ou seja, temos uma declaração

int * y[5];

Expressão x[0][0]é equivalente a y[0]e tem tipo int *. Vamos denotá-lo como z, ou seja, temos uma declaração

int *z;

expressão x[0][0][0]é equivalente à expressão y[0][0]que, por sua vez, é equivalente à expressão z[0]e tem tipo int.

Então nós temos

x[0] tem tipo int *[5]

x[0][0] tem tipo int *

x[0][0][0] tem tipo int

Então eles são objetos de tipos diferentes e, a propósito, de tamanhos diferentes.

Executar por exemplo

std::cout << sizeof( x[0] ) << std::endl;
std::cout << sizeof( x[0][0] ) << std::endl;
std::cout << sizeof( x[0][0][0] ) << std::endl;
Vlad de Moscou
fonte
10

Primeira coisa que tenho que dizer

x [0] = * (x + 0) = * x;

x [0] [0] = * (* (x + 0) + 0) = * * x;

x [0] [0] [0] = * (* (* (x + 0) + 0)) = * * * x;

Então * x ≠ * * x ≠ * * * x

Na figura a seguir, tudo é claro.

  x[0][0][0]= 2000

  x[0][0]   = 1001

  x[0]      = 10

insira a descrição da imagem aqui

É apenas um exemplo, onde o valor de x [0] [0] [0] = 10

e o endereço de x [0] [0] [0] é 1001

esse endereço é armazenado em x [0] [0] = 1001

e o endereço de x [0] [0] é 2000

e esse endereço é armazenado em x [0] = 2000

Então x [0] [0] [0] x [0] [0] x [0]

.

Edições

Programa 1:

{
int ***x;
x=(int***)malloc(sizeof(int***));
*x=(int**)malloc(sizeof(int**));
**x=(int*)malloc(sizeof(int*));
***x=10;
printf("%d   %d   %d   %d\n",x,*x,**x,***x);
printf("%d   %d   %d   %d   %d",x[0][0][0],x[0][0],x[0],x,&x);
}

Resultado

142041096 142041112 142041128 10
10 142041128 142041112 142041096 -1076392836

Programa 2:

{
int x[1][1][1]={10};
printf("%d   %d   %d   %d \n ",x[0][0][0],x[0][0],x[0],&x);
}

Resultado

10   -1074058436   -1074058436   -1074058436 
apm
fonte
3
Sua resposta é enganosa. x[0]não contém endereço de formiga. É uma matriz. Decairá apontar para o seu primeiro elemento.
haccks
Ummm ... o que isso significa? Sua edição é como cereja no bolo para sua resposta errada. Não faz sentido
haccks
@haccks Se estiver usando ponteiros sozinhos, esta resposta estará correta. Haverá algumas alterações na seção de endereço ao usar o Array
apm 21/11
7

Se você visualizasse as matrizes de uma perspectiva do mundo real, elas apareceriam da seguinte maneira:

x[0]é um contêiner de carga cheio de caixas.
x[0][0]é uma única caixa, cheia de caixas de sapatos, dentro do contêiner de carga.
x[0][0][0]é uma única caixa de sapatos dentro da caixa, dentro do contêiner de carga.

Mesmo que fosse a única caixa de sapatos na única caixa do contêiner de carga, ainda é uma caixa de sapatos e não um contêiner de carga

David Courtenay opcional
fonte
1
não x[0][0]haveria um único caixote cheio de pedaços de papel com as localizações das caixas de sapatos escritas?
Wchargin
4

Existe um princípio em C ++ para que: uma declaração de uma variável indique exatamente a maneira de usar a variável. Considere sua declaração:

int *(*x)[5];

que pode ser reescrito como (para maior clareza):

int *((*x)[5]);

Devido ao princípio, temos:

*((*x)[i]) is treated as an int value (i = 0..4)
 (*x)[i] is treated as an int* pointer (i = 0..4)
 *x is treated as an int** pointer
 x is treated as an int*** pointer

Portanto:

x[0] is an int** pointer
 x[0][0] = (x[0]) [0] is an int* pointer
 x[0][0][0] = (x[0][0]) [0] is an int value

Então você pode descobrir a diferença.

Nghia Bui
fonte
1
x[0]é uma matriz de 5 polegadas, não um ponteiro. (pode decair para um ponteiro na maioria dos contextos, mas a distinção é importante aqui).
7777 MM
Ok, mas você deve dizer: x [0] é uma matriz de 5 ponteiros int *
Nghia Bui
Para fornecer a derivação correta para @MattMcNabb: *(*x)[5]é um int, então (*x)[5]é um int *, então *xé um (int *)[5], então xé um *((int *)[5]). Ou seja, xé um ponteiro para uma matriz de 5 ponteiros para int.
Wchargin
2

Você está tentando comparar diferentes tipos por valor

Se você escolher os endereços, poderá obter mais do que espera

Lembre-se de que sua declaração faz a diferença

 int y [5][5][5];

permitiria que as comparações que você quer, uma vez que y, y[0], y[0][0], y[0][0][0]teria diferentes valores e tipos, mas o mesmo endereço

int **x[5];

não ocupa espaço contíguo.

xe x [0]têm o mesmo endereço, mas x[0][0]e x[0][0][0]são cada um em endereços diferentes

Glenn Teitelbaum
fonte
2
int *(*x)[5]é diferente deint **x[5]
MM
2

Sendo pum ponteiro: você está empilhando desreferências p[0][0], o que é equivalente a *((*(p+0))+0).

Na referência C (&) e na desreferência (*):

p == &p[0] == &(&p[0])[0] == &(&(&p[0])[0])[0])

É equivalente a:

p == &*(p+0) == &*(&*(p+0))+0 == &*(&*(&*(p+0))+0)+0

Veja que o & * pode ser refatorado, apenas removendo-o:

p == p+0 == p+0+0 == p+0+0+0 == (((((p+0)+0)+0)+0)+0)
Luciano
fonte
O que você está tentando mostrar com tudo após a sua primeira frase? Você apenas tem muitas variações p == p . &(&p[0])[0]é diferente dep[0][0]
MM
O cara perguntou por que 'x [0]! = X [0] [0]! = X [0] [0] [0]' quando x é um ponteiro, certo? Eu tentei mostrar a ele que ele pode ficar preso pela notação C de desreferência (*) quando ele empilhou [0] 's. Portanto, é uma tentativa de mostrar a ele a notação correta para que x seja igual a x [0], referenciando x [0] novamente com &, e assim por diante.
Luciano
1

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 xaponta 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 xcomo 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, xestá 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 xele 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 xe colocá-lo em algum lugar, então é exatamente isso que fazemos. Mas vamos em frente e colocá-lo no próprio x. Como &xtem 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 0xbfd9198cconté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á mallocpara criar a matriz de 5 ponteiros int e novamente para criar as entradas apontadas nessa matriz. mallocsempre 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!

Purag
fonte
Eu diria que outro uso estranho de ponteiros que eu já vi.
haccks
@haccks Sim, é bem estranho, mas quando você o divide, é tão básico quanto os outros exemplos. Apenas acontece que os padrões de bits são todos iguais.
Purag
Seu código causa comportamento indefinido. x[0]na verdade não representam um objeto válido do tipo correto
MM
@MattMcNabb É indefinido, e eu sou muito claro sobre isso, na verdade. Eu discordo sobre o tipo. xé um ponteiro para uma matriz, para que possamos usar o []operador para especificar um deslocamento desse ponteiro e desmarcá-lo. O que há de estranho aí? O resultado de x[0]é uma matriz, e C não se queixa se você imprimi-lo usando, %ppois é assim que é implementado de qualquer maneira.
Purag
E compilar isso com a -pedanticbandeira produz nenhum aviso, então C é muito bem com os tipos ...
Purag
0

O tipo de int *(*x)[5]é, por exemplo, int* (*)[5]um ponteiro para uma matriz de 5 ponteiros para ints.

  • xé o endereço da primeira matriz de 5 ponteiros para ints (um endereço com o tipo int* (*)[5])
  • x[0]o endereço da primeira matriz de 5 ponteiros para entradas (o mesmo endereço com o tipo int* [5]) (endereço de deslocamento x por exemplo, 0*sizeof(int* [5])índice * tamanho do tipo que está sendo apontado e desreferência)
  • x[0][0]é o primeiro ponteiro para um int na matriz (o mesmo endereço com o tipo int*) (endereço de deslocamento x por 0*sizeof(int* [5])e desreferencia e depois por 0*sizeof(int*)e desreferencia)
  • x[0][0][0]é o primeiro int sendo apontado pelo ponteiro para um int (endereço de deslocamento x por 0*sizeof(int* [5])e desreferencia e deslocamento desse endereço por 0*sizeof(int*)e desreferencia e deslocamento desse endereço por 0*sizeof(int)e desreferencia)

O tipo de int *(*y)[5][5][5]é, int* (*)[5][5][5]ou seja, um ponteiro para uma matriz 3d de ponteiros 5x5x5 para ints

  • x é o endereço da primeira matriz 3d de ponteiros 5x5x5 para ints com o tipo int*(*)[5][5][5]
  • x[0]é o endereço da primeira matriz 3d de ponteiros 5x5x5 para ints (endereço de deslocamento x por 0*sizeof(int* [5][5][5])e desreferencia)
  • x[0][0]é o endereço da primeira matriz 2D de ponteiros 5x5 para ints (desloca o endereço x por 0*sizeof(int* [5][5][5])e a desreferencia e desloca esse endereço por 0*sizeof(int* [5][5]))
  • x[0][0][0]é o endereço da primeira matriz de 5 ponteiros para ints (endereço de deslocamento x por 0*sizeof(int* [5][5][5])e desreferencial e deslocamento de endereço por 0*sizeof(int* [5][5])e deslocamento de endereço por 0*sizeof(int* [5]))
  • x[0][0][0][0]é o primeiro ponteiro para um int na matriz (deslocar o endereço x por 0*sizeof(int* [5][5][5])e desreferenciar e deslocar esse endereço por 0*sizeof(int* [5][5])e deslocar esse endereço por 0*sizeof(int* [5])e deslocar esse endereço por 0*sizeof(int*)e desreferenciar)
  • x[0][0][0][0][0]é o primeiro int sendo apontado pelo ponteiro para um int (endereço de deslocamento x por 0*sizeof(int* [5][5][5])e dereferência e deslocamento desse endereço por 0*sizeof(int* [5][5])e deslocamento desse endereço por 0*sizeof(int* [5])e deslocamento desse endereço por 0*sizeof(int*)e dereferência e deslocamento desse endereço por 0*sizeof(int)e dereferência)

Quanto à deterioração da matriz:

void function (int* x[5][5][5]){
  printf("%p",&x[0][0][0][0]); //get the address of the first int pointed to by the 3d array
}

Isso equivale a passar, int* x[][5][5]ou int* (*x)[5][5]seja, todos eles decaem para o último. É por isso que você não receberá um aviso do compilador para usar x[6][0][0]na função, mas receberá x[0][6][0]porque essas informações de tamanho são preservadas

void function (int* (*x)[5][5][5]){
  printf("%p",&x[0][0][0][0][0]); //get the address of the first int pointed to by the 3d array
}
  • x[0] é o endereço da primeira matriz 3d de ponteiros 5x5x5 para ints
  • x[0][0] é o endereço da primeira matriz 2D de ponteiros 5x5 para ints
  • x[0][0][0] é o endereço da primeira matriz de 5 ponteiros para ints
  • x[0][0][0][0] é o primeiro ponteiro para um int na matriz
  • x[0][0][0][0][0] é o primeiro int sendo apontado pelo ponteiro para um int

No último exemplo, é muito mais clara semanticamente para usar *(*x)[0][0][0]em vez de x[0][0][0][0][0], isto é porque a primeira e última [0]aqui são interpretados como uma desreferenciava ponteiro em vez de um índice para uma matriz multidimensional, devido ao tipo. No entanto, eles são idênticos porque, (*x) == x[0]independentemente da semântica. Você também pode usar *****x, que parece que você está desreferenciando o ponteiro 5 vezes, mas na verdade é interpretado exatamente da mesma maneira: um deslocamento, uma desreferência, uma desreferência, 2 deslocamentos em uma matriz e uma desreferência, apenas por causa do tipo você está aplicando a operação.

Essencialmente, quando você [0]ou *um *para um tipo não de matriz, é um deslocamento e uma desreferência devido à ordem de precedência de *(a + 0).

Quando você [0]ou *um *de um tipo de matriz, em seguida, ele é um deslocamento em seguida, um dereference idempotent (o dereference é resolvido pelo compilador para produzir o mesmo endereço - é uma operação idempotente).

Quando você [0]ou *um tipo com um tipo de matriz 1d, é um deslocamento e uma desreferência

Se você [0]ou **um tipo de matriz 2D, então é apenas um deslocamento, ou seja, um deslocamento e, em seguida, uma desreferência idempotente.

Se você [0][0][0]ou ***um tipo de matriz 3d, será uma desreferência offset + idempotente, uma desreferência offset + idempotente e uma desreferência offset + idempotente e uma desreferência. A desreferência verdadeira ocorre apenas quando o tipo de matriz é totalmente removido.

Para o exemplo do int* (*x)[1][2][3]tipo é desembrulhado em ordem.

  • x tem um tipo int* (*)[1][2][3]
  • *xtem um tipo int* [1][2][3](deslocamento 0 + desreferencia idempotente)
  • **xtem um tipo int* [2][3](deslocamento 0 + desreferencia idempotente)
  • ***xtem um tipo int* [3](deslocamento 0 + desreferencia idempotente)
  • ****xtem um tipo int*(deslocamento 0 + desreferencia)
  • *****xtem tipo int(deslocamento 0 + desreferência)
Lewis Kelsey
fonte