Puntero C a matriz / matriz de desambiguación de punteros

Cuál es la diferencia entre las siguientes declaraciones:

int* arr1[8]; int (*arr2)[8]; int *(arr3[8]); 

¿Cuál es la regla general para entender declaraciones más complejas?

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

El tercero es igual que el primero.

La regla general es la precedencia del operador . Puede llegar a ser mucho más complejo a medida que los indicadores de función entran en escena.

Use el progtwig cdecl , como lo sugiere 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> 

También trabaja de la otra manera.

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

No sé si tiene un nombre oficial, pero lo llamo Thingy (TM) de derecha a izquierda.

Comience por la variable, luego vaya a la derecha, a la izquierda, a la derecha … y así sucesivamente.

 int* arr1[8]; 

arr1 es una matriz de 8 punteros a enteros.

 int (*arr2)[8]; 

arr2 es un puntero (el paréntesis bloquea el derecho-izquierdo) a una matriz de 8 enteros.

 int *(arr3[8]); 

arr3 es una matriz de 8 punteros a enteros.

Esto debería ayudarte con declaraciones complejas.

 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 

La respuesta para los dos últimos también se puede deducir de la regla de oro en C:

La statement sigue al uso.

int (*arr2)[8];

¿Qué sucede si desreferencia arr2? Obtienes una matriz de 8 enteros.

int *(arr3[8]);

¿Qué pasa si tomas un elemento de arr3? Obtienes un puntero a un entero.

Esto también ayuda cuando se trata de punteros a funciones. Para tomar el ejemplo de sigjuice:

float *(*x)(void )

¿Qué sucede cuando eliminas la referencia x? Obtienes una función a la que puedes llamar sin argumentos. ¿Qué pasa cuando lo llamas? Devolverá un puntero a un flotador.

La precedencia del operador siempre es difícil, sin embargo. Sin embargo, el uso de paréntesis también puede ser confuso porque la statement sigue al uso. Al menos, para mí, intuitivamente arr2 parece una matriz de 8 punteros a enteros, pero en realidad es al revés. Solo me toma un tiempo acostumbrarme. Motivo suficiente para agregar siempre un comentario a estas declaraciones, si me preguntas 🙂

editar: ejemplo

Por cierto, me encontré con la siguiente situación: una función que tiene una matriz estática y que utiliza la aritmética del puntero para ver si el puntero de la fila está fuera de los límites. Ejemplo:

 #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; } 

Salida:

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

Tenga en cuenta que el valor del borde nunca cambia, por lo que el comstackdor puede optimizarlo. Esto es diferente de lo que inicialmente querría usar: const int (*border)[3] : que declara border como un puntero a una matriz de 3 enteros que no cambiará el valor mientras exista la variable. Sin embargo, ese puntero puede apuntar a cualquier otra matriz en cualquier momento. En su lugar, queremos ese tipo de comportamiento para el argumento (porque esta función no cambia ninguno de esos enteros). La statement sigue al uso.

(pd: ¡siéntete libre de mejorar esta muestra!)

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

Creo que podemos usar la regla simple …

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

ptr es un puntero a” ir hacia la derecha ..its “)” ahora vaya a la izquierda a “(” salir hacia la derecha “()” tan “a una función que no toma argumentos” ir a la izquierda “y devuelve un puntero” ir a la derecha “a una matriz” ir a la izquierda “de enteros”

Como regla general, los operadores unarios derechos (como [] , () , etc.) tienen preferencia sobre los operadores izquierdos. Entonces, int *(*ptr)()[]; sería un puntero que apunta a una función que devuelve una matriz de punteros a int (obtenga los operadores correctos tan pronto como pueda a medida que sale del paréntesis)

Así es como lo interpreto:

 int *something[n]; 

nota sobre la precedencia: el operador del subíndice de matriz (‘[]’) tiene mayor prioridad que el operador de referencia (‘*’).

Entonces, aquí aplicaremos el ‘[]’ antes de ‘*’, haciendo que la statement sea equivalente a:

 int *(something[i]); 

nota sobre cómo una statement tiene sentido: int num significa (num) es un (int), int *ptr o int (*ptr) significa, (valor en ptr) es un (int), lo que hace que ptr sea un puntero a int.

Esto se puede leer como, (el valor de (valor en el índice ith del algo)) es un número entero. Entonces, (valor en el i-ésimo índice de algo) es un (puntero entero), que hace que algo sea una matriz de punteros enteros.

En el segundo,

 int (*something)[n]; 

Para darle sentido a esta afirmación, debes estar familiarizado con este hecho:

nota sobre la representación del puntero de la matriz: algoElse [i] es equivalente a * (algoElse + i)

Entonces, reemplazando algo con (* algo), obtenemos * (* algo + i), que es un número entero según la statement. Entonces, (* algo) nos dio una matriz, que hace algo equivalente a (apunta a una matriz).

Creo que la segunda statement es confusa para muchos. Aquí hay una manera fácil de entenderlo.

Vamos a tener una matriz de enteros, es decir, int B[8] .

Tengamos también una variable A que apunte a B. Ahora, el valor en A es B, es decir (*A) == B Por lo tanto, A apunta a una matriz de enteros. En tu pregunta, arr es similar a A.

De forma similar, en int* (*C) [8] , C es un puntero a una matriz de punteros a entero.

Aquí hay un sitio web interesante que explica cómo leer tipos complejos en C: http://www.unixwiz.net/techtips/reading-cdecl.html

En el puntero a un entero si el puntero se incrementa, pasa al entero siguiente.

en conjunto de puntero si el puntero se incrementa, salta a la siguiente matriz