¿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 las 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 las declaraciones más complejas?
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers
La tercera es igual que la primera.
La regla general es precedencia de los operadores . Puede ser incluso mucho más complejo cuando los punteros de función entran en escena.
Utiliza el programa cdecl, como 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 funciona a la inversa.
cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
No sé si tiene un nombre oficial, pero yo lo llamo el Right-Left Thingy(TM).
Empieza por la variable, luego ve a la derecha, y a la izquierda, y a la derecha... y así sucesivamente.
int* arr1[8];
arr1 es un array de 8 punteros a enteros.
int (*arr2)[8];
arr2 es un puntero (el paréntesis bloquea la derecha-izquierda) a un Array de 8 enteros.
int *(arr3[8]);
arr3 es un array de 8 punteros a enteros.
Esto debería ayudarte con las declaraciones complejas.
La respuesta para las dos últimas también se puede deducir de la regla de oro en C:
La declaración sigue al uso.
int (*arr2)[8];
¿Qué sucede si se hace referencia a arr2? Obtienes un Array de 8 enteros.
int *(arr3[8]);
¿Qué ocurre si se toma 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é ocurre cuando se dereferencia x? Obtienes una función que puedes llamar sin argumentos. ¿Qué ocurre cuando la llamas? Que devolverá un puntero a un flotador.
Sin embargo, la precedencia de los operadores 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 arr2 parece un Array de 8 punteros a ints, pero en realidad es al revés. Sólo hay que acostumbrarse. Razón suficiente para añadir siempre un comentario a estas declaraciones, en mi opinión :)
editar: ejemplo
Por cierto, acabo de tropezar con la siguiente situación: una función que tiene una matriz estática y que utiliza la aritmética de punteros para ver si el puntero de la fila está fuera de los límites. Ejemplo:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}
La 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 de border nunca cambia, por lo que el compilador puede optimizarlo. Esto es diferente de lo que usted podría querer usar inicialmente: const int (*border)[3]
que declara la frontera como un puntero a un Array de 3 enteros que no cambiará de valor mientras exista la variable. Sin embargo, ese puntero puede apuntar a cualquier otro Array de este tipo en cualquier momento. Nosotros queremos ese tipo de comportamiento para el argumento, en cambio (porque esta función no cambia ninguno de esos enteros). La declaración sigue al uso.
(p.d.: siéntase libre de mejorar esta muestra)
Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.