He escuchado a mucha gente decir que cuando queremos pasar un arreglo 1D a una función fun los siguientes prototipos son equivalentes:
1.
int fun(int a[]); int fun(int a[10]); int fun(int *a); Incluso escuché a personas decir que el primero y el segundo se convierten internamente en el tercero en C. Supongo que esto es cierto porque hacer algo como sizeof(a) en la definición de la función declarada en 2 da el tamaño de un puntero en bytes (y no 10*sizeof(int)).
Dicho esto, he visto textos que afirman que para pasar una matriz 2D a una función, los siguientes son equivalentes:
1.
int fun(int a[][10]); int fun(int (*a)[10]);Y aquí nuevamente he escuchado a la gente decir que en C, el primero se convierte internamente en el segundo. Si eso es cierto, lo siguiente debería haber sido equivalente, ¿verdad?
1.
int fun(int a[][]); int fun(int (*a)[]);Pero desafortunadamente, el primero presenta un error de compilación, pero el segundo no:
1 | int fun(int a[][]); | ^ tc:2:13: note: declaration of 'a' as multidimensional array must have bounds for all dimensions except the first Esto me hace sentir que C está tratando a en el primero como una matriz multidimensional, cada uno de cuyos elementos es una matriz de enteros pero su tipo no está completo (int [] a saber).
Mientras que en el segundo, a es solo un puntero a una matriz de enteros (con tamaño no especificado o tipo incompleto). Y los dos son realmente diferentes y un formato no es equivalente al otro...
¿Alguien puede guiarme en detalles sobre lo que realmente sucede en C, en cada uno de estos casos?
Primero, las reglas para las declaraciones dicen que el tipo de elemento de una matriz debe estar completo, según C 2018 6.7.6.2 1. Por lo tanto, int a[][] obtiene un error de compilación ya que el primer [] especifica una matriz cuyos elementos serían int [] , que está incompleto.
Después de analizar la declaración, la declaración de un parámetro de función para que sea una matriz se ajusta para que sea un puntero, según C 2018 6.7.6.3 7.
int (*a)[] está permitido sin error porque no existe una regla que indique que un puntero debe apuntar a un tipo completo. (Si se realiza aritmética en el puntero, entonces el tipo apuntado debe estar completo, según C 2018 6.5.6 2 y 3).
La regla relevante se encuentra en C17 6.7.6.3/7:
Una declaración de un parámetro como ''matriz de tipo '' se ajustará a ''puntero calificado a tipo '', donde los calificadores de tipo (si los hay) son los especificados dentro de [ y ] de la derivación del tipo de matriz
Esto a veces se denomina informalmente "decaimiento de matriz" y es similar a la regla en la que se usa un identificador de matriz en una expresión.
Incluso he escuchado a personas decir que el primero y el segundo se convierten internamente en el tercero en C
Sí, eso es correcto, según la regla citada anteriormente. Las 3 declaraciones en su primer ejemplo son 100% equivalentes.
Ahora bien, he visto textos que afirman que para pasar un array 2D a una función son equivalentes los siguientes: /--/
Y aquí nuevamente he escuchado a la gente decir que en C, el primero se convierte internamente en el segundo.
Correcto.
int fun(int a[][]); es una declaración inválida porque en realidad es una matriz de tipos de matriz incompleta, donde todos los elementos de cada matriz son un tipo incompleto de int . C no permite declaraciones de arreglos con elementos de tipo incompleto.
C17 6.7.6.2/1
El tipo de elemento no debe ser un tipo incompleto o de función.
Sin embargo, podemos dejar la dimensión más externa con un tipo de matriz incompleta, ya que se ajusta a un puntero de todos modos, lo que hace que su tamaño sea irrelevante. Pero eso no se puede hacer para las dimensiones internas según la regla anterior de que los elementos de las matrices deben ser de un tipo completo. (Tampoco podemos tener matrices de tipos de estructuras incompletas).
int (*a)[] es válido ya que es un puntero a una matriz de tipo incompleto. De manera similar, C nos permite usar punteros a tipos de estructura incompletos, pero no podemos declarar objetos de un tipo de estructura incompleto.