¿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?
¿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?
const
yvolatile
, que son importantes y difíciles, faltan en ese artículo.Respuestas:
El tercero es el mismo que el primero.
La regla general es la precedencia del operador . Puede volverse aún más complejo a medida que los punteros de función entran en escena.
fuente
( ) [ ]
asocian de izquierda a derecha y tienen una mayor precedencia que*
por lo leeint* arr[8]
como una matriz de tamaño 8 donde cada elemento apunta a un int yint (*arr)[8]
como un puntero a una matriz de tamaño 8 que contiene números enterosUse el programa cdecl , como lo sugiere K&R.
También trabaja de la otra manera.
fuente
No sé si tiene un nombre oficial, pero lo llamo el Right-Left Thingy (TM).
Comience en la variable, luego vaya a la derecha, a la izquierda, a la derecha ... y así sucesivamente.
arr1
es una matriz de 8 punteros a enteros.arr2
es un puntero (el paréntesis bloquea la derecha-izquierda) a una matriz de 8 enteros.arr3
es una matriz de 8 punteros a enteros.Esto debería ayudarte con declaraciones complejas.
fuente
int *a[][10]
mientras que el segundo tiene éxito.( ) [ ]
izquierda a derecha y de derecha a izquierda de* &
fuente
[5]
) representa la dimensión interna. Esto significa que(*a[8])
es la primera dimensión y, por lo tanto, es la representación externa de la matriz. A lo quea
apunta cada elemento es a una matriz entera diferente de tamaño 5.La respuesta para los dos últimos también se puede deducir de la regla de oro en C:
int (*arr2)[8];
¿Qué pasa si desreferencias
arr2
? Obtiene una matriz de 8 enteros.int *(arr3[8]);
¿Qué sucede 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é pasa cuando desreferencias
x
? Obtiene una función que puede llamar sin argumentos. ¿Qué pasa cuando lo llamas? Devolverá un puntero a afloat
.Sin embargo, la precedencia del operador siempre es complicada. Sin embargo, el uso de paréntesis también puede ser confuso porque la declaración sigue al uso. Al menos, para mí, intuitivamente se
arr2
ve como una matriz de 8 punteros a ints, pero en realidad es al revés. Solo toma un tiempo acostumbrarse. Razón suficiente para agregar siempre un comentario a estas declaraciones, si me preguntas :)editar: ejemplo
Por cierto, me topé con la siguiente situación: una función que tiene una matriz estática y que usa la aritmética del puntero para ver si el puntero de la fila está fuera de los límites. Ejemplo:
Salida:
Tenga en cuenta que el valor del borde nunca cambia, por lo que el compilador puede optimizarlo. Esto es diferente de lo que podría querer usar inicialmente
const int (*border)[3]
:: que declara el borde 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 de este tipo en cualquier momento. En cambio, queremos ese tipo de comportamiento para el argumento (porque esta función no cambia ninguno de esos enteros). La declaración sigue al uso.(pd: ¡siéntase libre de mejorar esta muestra!)
fuente
fuente
Como regla general, los operadores unitarios adecuados (como
[]
,()
, etc.) tienen preferencia sobre los de izquierda. Entonces,int *(*ptr)()[];
lo 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)fuente
error: ‘foo’ declared as function returning an array int foo(int arr_2[5][5])[5];
bajo GCC 8 con$ gcc -std=c11 -pedantic-errors test.c
int *(*ptr)();
permite que una expresión comop()[3]
(o(*p)()[3]
) se use más adelante.int *foo(int arr_2[5][5]) { return &(arr_2[2][0]); }
y llámalo así: ¿foo(arr)[4];
cuál debería contenerarr[2][4]
, verdad?Creo que podemos usar la regla simple ...
"
ptr
es un puntero para" ir hacia la derecha ... es ")" ahora ir a la izquierda es un "(" salir a la derecha "()" entonces "a una función que no toma argumentos" ir a la izquierda "y devuelve un puntero" ir derecha "a una matriz" ir a la izquierda "de enteros"fuente
)
, ahora ir a la izquierda ... es*
"un puntero a" ir a la derecha ... es)
, ahora ir a la izquierda ... es un(
salir, ir a la derecha()
por lo que "a una función que no tiene argumentos" anda bien ...[]
"y devuelve una matriz de" ir a la derecha;
final, así que ir a la izquierda ...*
"punteros" a ir a la izquierda ...int
"enteros"Aquí hay un sitio web interesante que explica cómo leer tipos complejos en C: http://www.unixwiz.net/techtips/reading-cdecl.html
fuente
Así es como lo interpreto:
Entonces, aquí aplicaremos el
[]
antes*
, haciendo que la declaración sea equivalente a:Esto se puede leer como, (el valor del (valor en el índice i-ésimo de algo)) es un número entero. Entonces, (el valor en el i-ésimo índice de algo) es un (puntero entero), lo que hace que algo sea una matriz de punteros enteros.
En el segundo
Para que esta afirmación tenga sentido, debe estar familiarizado con este hecho:
Entonces, reemplazando
somethingElse
con(*something)
, obtenemos*(*something + i)
, que es un número entero según la declaración. Entonces,(*something)
nos dio una matriz, que hace algo equivalente a (puntero a una matriz) .fuente
Supongo que la segunda declaración es confusa para muchos. Aquí hay una manera fácil de entenderlo.
Tengamos una variedad de enteros, es decir
int B[8]
.También tengamos una variable A que apunta a B. Ahora, el valor en A es B, es decir
(*A) == B
. Por lo tanto, A apunta a una matriz de enteros. En su pregunta, arr es similar a A.Del mismo modo, en
int* (*C) [8]
, C es un puntero a una matriz de punteros a entero.fuente
En esta declaración,
arr1
hay una matriz de 5 punteros a enteros. Motivo: Los corchetes tienen mayor prioridad sobre * (operador de desreferencia). Y en este tipo, el número de filas es fijo (5 aquí), pero el número de columnas es variable.En esta declaración,
arr2
es un puntero a una matriz entera de 5 elementos. Motivo: Aquí, los corchetes () tienen mayor prioridad que []. Y en este tipo, el número de filas es variable, pero el número de columnas es fijo (5 aquí).fuente
En puntero a un entero si el puntero se incrementa, entonces pasa al siguiente entero.
en la matriz del puntero si se incrementa el puntero, salta a la siguiente matriz
fuente