C ponteiro para array / array de desambiguação de pointers

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?

 int* arr[8]; // An array of int pointers. int (*arr)[8]; // A pointer to an array of integers 

O terceiro é o mesmo que o primeiro.

A regra geral é a precedência do operador . Pode ficar ainda mais complexo à medida que os pointers de function entram em cena.

Use o programa cdecl , como sugerido por K & R.

 $ cdecl Type `help' or `?' for help cdecl> explain int* arr1[8]; declare arr1 as array 8 of pointer to int cdecl> explain int (*arr2)[8] declare arr2 as pointer to array 8 of int cdecl> explain int *(arr3[8]) declare arr3 as array 8 of pointer to int cdecl> 

Isso funciona do outro jeito também.

 cdecl> declare x as pointer to function(void) returning pointer to float float *(*x)(void ) 

Não sei se tem um nome oficial, mas chamo-lhe o Direito-Esquerdo Thingy (TM).

Comece na variável, depois vá para a direita e para a esquerda e para a direita … e assim por diante.

 int* arr1[8]; 

arr1 é uma matriz de 8 pointers para números inteiros.

 int (*arr2)[8]; 

arr2 é um ponteiro (o parêntese bloqueia a direita-esquerda) para uma matriz de 8 inteiros.

 int *(arr3[8]); 

arr3 é uma matriz de 8 pointers para inteiros.

Isso deve ajudá-lo com declarações complexas.

 int *a[4]; // Array of 4 pointers to int int (*a)[4]; //a is a pointer to an integer array of size 4 int (*a[8])[5]; //a is an array of pointers to integer array of size 5 

A resposta para os dois últimos também pode ser deduzida da regra de ouro em C:

Declaração segue o uso.

int (*arr2)[8];

O que acontece se você desconsiderar o arr2? Você obtém uma matriz de 8 inteiros.

int *(arr3[8]);

O que acontece se você pegar um elemento de arr3? Você obtém um ponteiro para um inteiro.

Isso também ajuda quando se lida com pointers para funções. Para pegar o exemplo do sigjuice:

float *(*x)(void )

O que acontece quando você desrefere x? Você obtém uma function que pode chamar sem argumentos. O que acontece quando você liga? Ele retornará um ponteiro para um float.

A precedência do operador é sempre complicada, no entanto. No entanto, usar parênteses também pode ser confuso porque a declaração segue o uso. Pelo menos para mim, intuitivamente arr2 se parece com uma matriz de 8 pointers para ints, mas na verdade é o contrário. Leva algum tempo para se acostumar. Razão suficiente para sempre adicionar um comentário a estas declarações, se você me perguntar 🙂

edit: example

By the way, eu apenas tropeçou na seguinte situação: uma function que tem uma matriz estática e que usa aritmética de ponteiro para ver se o ponteiro de linha está fora dos limites. Exemplo:

 #include  #include  #include  #define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0])) int * put_off(const int newrow[2]) { static int mymatrix[3][2]; static int (*rowp)[2] = mymatrix; int (* const border)[] = mymatrix + NUM_ELEM(mymatrix); memcpy(rowp, newrow, sizeof(*rowp)); rowp += 1; if (rowp == border) { rowp = mymatrix; } return *rowp; } int main(int argc, char *argv[]) { int i = 0; int row[2] = {0, 1}; int *rout; for (i = 0; i < 6; i++) { row[0] = i; row[1] += i; rout = put_off(row); printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]); } return 0; } 

Saída:

  0 (0x804a02c): [0, 0]
 1 (0x804a034): [0, 0]
 2 (0x804a024): [0, 1]
 3 (0x804a02c): [1, 2]
 4 (0x804a034): [2, 4]
 5 (0x804a024): [3, 7] 

Observe que o valor da borda nunca muda, portanto, o compilador pode otimizar isso. Isso é diferente do que você pode querer usar inicialmente: const int (*border)[3] : que declara a borda como um ponteiro para uma matriz de 3 inteiros que não alterará o valor enquanto a variável existir. No entanto, esse ponteiro pode ser apontado para qualquer outro array a qualquer momento. Nós queremos esse tipo de comportamento para o argumento, em vez disso (porque essa function não altera nenhum desses inteiros). Declaração segue o uso.

(ps: sinta-se livre para melhorar esta amostra!)

 typedef int (*PointerToIntArray)[]; typedef int *ArrayOfIntPointers[]; 

Acho que podemos usar a regra simples

 example int * (*ptr)()[]; start from ptr 

ptr é um ponteiro para” ir para a direita ..its “)” agora vá para a esquerda a sua “(” sair ir para a direita “()” so “para uma function que não recebe argumentos” ir para a esquerda “e retorna um ponteiro” vá para a direita “para um array” vá para a esquerda “de inteiros”

Como regra geral, os operadores unários da direita (como [] , () , etc) têm preferência sobre os da esquerda. Então, int *(*ptr)()[]; seria um ponteiro que aponta para uma function que retorna uma matriz de pointers para int (obtenha os operadores certos assim que puder, ao sair dos parênteses)

Veja como eu interpreto:

 int *something[n]; 

note na precedência: o operador de matriz subscrito (‘[]’) tem maior prioridade que o operador de remoção de referência (‘*’).

Então, aqui vamos aplicar o ‘[]’ antes de ‘*’, tornando a declaração equivalente a:

 int *(something[i]); 

nota sobre como uma declaração faz sentido: int num significa (num) é um (int), int *ptr ou int (*ptr) significa, (valor em ptr) é um (int), o que torna ptr um ponteiro para int.

Isto pode ser lido como, (valor do (valor no ith índice do algo)) é um inteiro. Então, (valor no índice i de algo) é um (ponteiro inteiro), o que faz de algo uma matriz de pointers inteiros.

No segundo,

 int (*something)[n]; 

Para entender essa declaração, você deve estar familiarizado com esse fato:

nota sobre a representação ponteiro do array: somethingElse [i] é equivalente a * (somethingElse + i)

Então, substituindo somethingElse por (* alguma coisa), obtemos * (* algo + i), que é um inteiro como por declaração. Então, (* alguma coisa) nos deu uma matriz, que faz algo equivalente a (ponteiro para uma matriz).

Eu acho que a segunda declaração é confusa para muitos. Aqui está uma maneira fácil de entender isso.

Vamos ter uma matriz de 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 inteiros. Na sua pergunta, arr é semelhante a A.

Da mesma forma, em int* (*C) [8] , C é um ponteiro para uma matriz de pointers para inteiro.

Aqui está um site interessante que explica como ler tipos complexos em C: http://www.unixwiz.net/techtips/reading-cdecl.html

No ponteiro para um inteiro, se o ponteiro for incrementado, ele será o próximo inteiro.

na matriz do ponteiro se o ponteiro for incrementado, ele salta para a próxima matriz