¿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 comprender declaraciones más complejas?
Jorge
¿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 comprender declaraciones más complejas?
jugo de sig
Utilizar el cdecl programa, 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 )
@ankii La mayoría de las distribuciones de Linux deberían tener un paquete. También puede construir su propio binario.
– jugo de sig
15 oct 2019 a las 17:05
ah, lo siento por no mencionar, macOS aquí. Veré si está disponible, de lo contrario, el sitio web también está bien. ^^ gracias por informarme sobre esto. Siéntase libre de marcar NLN.
– usuario10063119
15 oct 2019 a las 17:06
@ankii Puede instalar desde Homebrew (¿y tal vez MacPorts?). Si no son de su agrado, es trivial crear uno propio desde el enlace de Github en la parte superior derecha de cdecl.org (lo acabo de crear en macOS Mojave). Luego simplemente copie el binario cdecl en su RUTA. Recomiendo $PATH/bin, porque no hay necesidad de involucrar a root en algo tan simple como esto.
– jugo de sig
15 oct 2019 a las 17:18
Oh, no había leído el pequeño párrafo sobre la instalación en Léame. solo algunos comandos y banderas para manejar dependencias. Instalado usando brew. 🙂
– usuario10063119
15 oct 2019 a las 17:35
He oído referirse a ella con el nombre de “La regla de la espiral”, que se puede encontrar aquí.
– fouric
27 de mayo de 2013 a las 3:04
@InkBlend: la regla espiral es diferente de regla derecha-izquierda. El primero falla en casos como int *a[][10]
mientras que este último lo consigue.
– leyendas2k
9 oct 2013 a las 13:51
Como dijeron InkBlend y legends2k, esta es la regla espiral, que es más compleja y no funciona en todos los casos, por lo que no hay razón para usarla.
– kotlomoy
25/09/2014 a las 18:29
No olvide la asociatividad de izquierda a derecha de ( ) [ ]
y de derecha a izquierda de * &
– blanda
23 de septiembre de 2017 a las 14:10
@legends2k: ¿Cuál es la lectura de declaración para int *a?[][10]
– Chico bestia
21 de noviembre de 2018 a las 4:37
La respuesta para los dos últimos también se puede deducir de la regla de oro en C:
La declaración sigue al uso.
int (*arr2)[8];
¿Qué pasa si desreferencias? arr2
? Obtienes una matriz de 8 enteros.
int *(arr3[8]);
¿Qué pasa si tomas un elemento de arr3
? Obtienes un puntero a un número entero.
Esto también ayuda cuando se trata de punteros a funciones. Para tomar el ejemplo de sigjuice:
float *(*x)(void )
¿Qué sucede cuando desreferencias? x
? Obtienes una función a la que puedes llamar sin argumentos. ¿Qué pasa cuando lo llamas? Devolverá un puntero a un float
.
Sin embargo, la precedencia de los operadores siempre es complicada. Sin embargo, el uso de paréntesis también puede resultar confuso porque la declaración 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 toma algo de 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 aritmética de punteros para ver si el puntero de 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;
}
Producción:
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 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án de valor mientras exista la variable. Sin embargo, ese puntero puede apuntar a cualquier otra matriz 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éntete libre de mejorar esta muestra!)
gary
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
Abhishek Jaisingh
Aquí hay un sitio web interesante que explica cómo leer tipos complejos en C:
http://www.unixwiz.net/techtips/reading-cdecl.html
Aquí hay un gran artículo sobre la lectura de declaraciones complejas en C: unixwiz.net/techtips/reading-cdecl.html
– bufón
27/01/2013 a las 13:00
@jesper Desafortunadamente, el
const
yvolatile
los calificadores, que son importantes y complicados, faltan en ese artículo.– no-un-usuario
18 mayo 2017 a las 15:32