Qual é a diferença entre as seguintes declarações:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
Qual é a regra geral para entender declarações mais complexas?
c
arrays
pointers
variable-declaration
George
fonte
fonte
const
evolatile
, que são importantes e complicados, estão faltando nesse artigo.Respostas:
O terceiro é o mesmo que o primeiro.
A regra geral é a precedência do operador . Pode ficar ainda mais complexo à medida que ponteiros de função entram em cena.
fonte
( ) [ ]
associam da esquerda para a direita e tem precedência maior do que*
assim que lerint* arr[8]
como uma matriz de tamanho 8 onde cada elemento aponta para um int eint (*arr)[8]
como um ponteiro para uma matriz de tamanho 8 que contém números inteirosUse o programa cdecl , conforme sugerido pela K&R.
Isso funciona do outro jeito também.
fonte
Não sei se ele tem um nome oficial, mas o chamo de Thingy Direita Esquerda (TM).
Comece na variável, depois vá para a direita, esquerda e direita ... e assim por diante.
arr1
é uma matriz de 8 ponteiros para números inteiros.arr2
é um ponteiro (o parêntese bloqueia a direita esquerda) para uma matriz de 8 números inteiros.arr3
é uma matriz de 8 ponteiros para números inteiros.Isso deve ajudá-lo com declarações complexas.
fonte
int *a[][10]
enquanto o último consegue.( ) [ ]
e da direita para esquerda* &
fonte
[5]
) representa a dimensão interna. Isso significa que(*a[8])
é a primeira dimensão e, portanto, é a representação externa da matriz. O que cada elemento dentroa
aponta para um array de inteiros diferente de tamanho 5.A resposta para os dois últimos também pode ser deduzida da regra de ouro em C:
int (*arr2)[8];
O que acontece se você desreferenciar
arr2
? Você obtém uma matriz de 8 números inteiros.int *(arr3[8]);
O que acontece se você retirar um elemento
arr3
? Você recebe um ponteiro para um número inteiro.Isso também ajuda ao lidar com ponteiros para funções. Para pegar o exemplo de sigjuice:
float *(*x)(void )
O que acontece quando você desreferencia
x
? Você obtém uma função que você pode chamar sem argumentos. O que acontece quando você chama? Ele retornará um ponteiro para afloat
.A precedência do operador é sempre complicada, no entanto. No entanto, o uso de parênteses também pode ser confuso, pois a declaração segue o uso. Pelo menos, para mim, intuitivamente
arr2
parece uma matriz de 8 ponteiros para ints, mas na verdade é o contrário. Apenas leva algum tempo para se acostumar. Motivo suficiente para sempre adicionar um comentário a essas declarações, se você me perguntar :)edit: exemplo
A propósito, acabei de me deparar com a seguinte situação: uma função que tem uma matriz estática e usa aritmética do ponteiro para verificar se o ponteiro da linha está fora dos limites. Exemplo:
Resultado:
Observe que o valor da borda nunca muda, então o compilador pode otimizar isso. Isso é diferente do que você pode querer inicialmente usar::
const int (*border)[3]
que declara a borda como um ponteiro para uma matriz de 3 números inteiros que não alterará o valor enquanto a variável existir. No entanto, esse ponteiro pode ser apontado para qualquer outra matriz a qualquer momento. Em vez disso, queremos esse tipo de comportamento (porque essa função não altera nenhum desses números inteiros). A declaração segue o uso.(ps: fique à vontade para melhorar esta amostra!)
fonte
fonte
Como regra geral, os operadores unários direito (como
[]
,()
, etc) têm preferência sobre os de esquerda. Portanto,int *(*ptr)()[];
seria um ponteiro que aponta para uma função que retorna uma matriz de ponteiros para int (obtenha os operadores corretos o mais rápido possível, assim que sair do parêntese)fonte
error: ‘foo’ declared as function returning an array int foo(int arr_2[5][5])[5];
sob o GCC 8 com$ gcc -std=c11 -pedantic-errors test.c
int *(*ptr)();
permite que uma expressão comop()[3]
(ou(*p)()[3]
) seja usada posteriormente.int *foo(int arr_2[5][5]) { return &(arr_2[2][0]); }
e chame assim: ofoo(arr)[4];
que deve conterarr[2][4]
, certo?Eu acho que podemos usar a regra simples ..
"
ptr
é um ponteiro para" ir para a direita .. seu ") agora vá para a esquerda é um" ("saia para a direita" () "so" para uma função que não aceita argumentos "vá para a esquerda" e retorna um ponteiro "go direita "para uma matriz" vá para a esquerda "de números inteiros"fonte
)
, agora vá para a esquerda ... é*
"um ponteiro para" vá para a direita ... é)
, agora vá para a esquerda ... é a(
sair, vá()
para a direita "para uma função que não aceita argumentos" vá para a direita ...[]
"e retorne uma matriz de" vá para a direita;
, então vá para a esquerda ...*
"ponteiros para" vá para a esquerda ...int
"números inteiros"Aqui está um site interessante que explica como ler tipos complexos em C: http://www.unixwiz.net/techtips/reading-cdecl.html
fonte
Aqui está como eu o interpreto:
Então, aqui aplicaremos o
[]
antes*
, tornando a declaração equivalente a:Isso pode ser lido como, (o valor de (valor no i-ésimo índice de alguma coisa)) é um número inteiro. Portanto, (o valor no i-ésimo índice de alguma coisa) é um (ponteiro inteiro), o que torna o algo uma matriz de ponteiros inteiros.
No segundo,
Para entender essa afirmação, você deve estar familiarizado com este fato:
Então, substituindo
somethingElse
por(*something)
, obtemos*(*something + i)
, que é um número inteiro conforme a declaração. Então,(*something)
nos deu uma matriz, que faz algo equivalente a (ponteiro para uma matriz) .fonte
Eu acho que a segunda declaração é confusa para muitos. Aqui está uma maneira fácil de entender isso.
Vamos ter uma matriz de números inteiros, ou seja
int B[8]
.Vamos também ter uma variável A que aponta para B. Agora, o valor em A é B, ie
(*A) == B
. Portanto, A aponta para uma matriz de números inteiros. Na sua pergunta, arr é semelhante a A.Da mesma forma, em
int* (*C) [8]
, C é um ponteiro para uma matriz de ponteiros para um número inteiro.fonte
Nesta declaração,
arr1
há uma matriz de 5 ponteiros para números inteiros. Motivo: colchetes têm maior precedência sobre * (operador de desreferenciamento). E nesse tipo, o número de linhas é fixo (5 aqui), mas o número de colunas é variável.Nesta declaração,
arr2
é um ponteiro para uma matriz inteira de 5 elementos. Razão: Aqui, colchetes () têm maior precedência que []. E nesse tipo, o número de linhas é variável, mas o número de colunas é fixo (5 aqui).fonte
No ponteiro para um número inteiro, se o ponteiro for incrementado, ele será o próximo número inteiro.
na matriz do ponteiro se o ponteiro for incrementado, ele pula para a próxima matriz
fonte