¿Por qué es function (char * array ) una definición de función válida pero no (char (* array) en C?

Creo que es porque el primero es una matriz de punteros a char y el último es un puntero a una matriz de caracteres, y necesitamos especificar correctamente el tamaño del objeto al que se apunta para nuestra definición de función. En la antigua;

function(char * p_array[]) 

el tamaño del objeto al que se apunta ya está incluido (es un puntero a char), pero este último

 function(char (*p_array)[]) 

¿Necesita el tamaño de la matriz a la que apunta p_array como parte de la definición de p_array? Estoy en la etapa en la que he estado pensando en esto durante demasiado tiempo y me he confundido, alguien, por favor, avíseme si mi razonamiento es correcto.

Ambos son válidos en C pero no en C ++ . Normalmente estarías en lo correcto:

 char *x[]; // array of pointers to char char (*y)[]; // pointer to array of char 

Sin embargo, las matrices decaen a los punteros si aparecen como parámetros de función. Así se convierten en:

 char **x; // Changes to pointer to array of pointer to char char (*y)[]; // No decay, since it's NOT an array, it's a pointer to an array 

En un tipo de matriz en C, se permite que uno de los tamaños no se especifique. Este debe ser el que está más a la izquierda (gritos, dije al principio que estaba más a la derecha). Asi que,

 int valid_array[][5]; // Ok int invalid_array[5][]; // Wrong 

(Puedes encadenarlos … pero rara vez tenemos razones para hacerlo …)

 int (*convoluted_array[][5])[][10]; 

Hay un retén, y el retén es que un tipo de matriz con [] es un tipo incompleto. Puede pasar un puntero a un tipo incompleto, pero ciertas operaciones no funcionarán, ya que necesitan un tipo completo. Por ejemplo, esto no funcionará:

 void func(int (*x)[]) { x[2][5] = 900; // Error } 

Esto es un error porque para encontrar la dirección de x[2] , el comstackdor necesita saber qué tan grandes son x[0] x[1] . Pero x[0] y x[1] tienen el tipo int [] – un tipo incompleto sin información sobre qué tan grande es. Esto se vuelve más claro si se imagina cuál sería la versión “no descompuesta” del tipo, que es int x[][] : obviamente no es válida C. Si desea pasar una matriz bidimensional en C, tiene Algunas opciones:

  • Pase una matriz unidimensional con un parámetro de tamaño.

     void func(int n, int x[]) { x[2*n + 5] = 900; } 
  • Utilice una matriz de punteros a las filas. Esto es un poco torpe si tiene datos 2D genuinos.

     void func(int *x[]) { x[2][5] = 900; } 
  • Use un tamaño fijo.

     void func(int x[][5]) { x[2][5] = 900; } 
  • Use una matriz de longitud variable (solo C99, por lo que probablemente no funcione con los comstackdores de Microsoft).

     // There's some funny syntax if you want 'x' before 'width' void func(int n, int x[][n]) { x[2][5] = 900; } 

Esta es un área de problemas frecuentes incluso para los veteranos C. Muchos idiomas carecen de soporte intrínseco “fuera de la caja” para arreglos multidimensionales (tamaño C ++, Java, Python) reales, de tamaño variable, aunque algunos idiomas sí lo tienen (Common Lisp, Haskell, Fortran). Verá una gran cantidad de código que utiliza matrices de matrices o que calcula las compensaciones de matrices manualmente.

Esas dos declaraciones son muy diferentes. En una statement de parámetros de función, un declarador de [] aplicado directamente al nombre del parámetro es completamente equivalente a un * , por lo que su primera statement es exactamente la misma en todos los aspectos que esto:

 function(char **p_array); 

Sin embargo, esto no se aplica recursivamente a los tipos de parámetros. Su segundo parámetro tiene el tipo char (*)[] , que es un puntero a una matriz de tamaño desconocido, es un puntero a un tipo incompleto. Con mucho gusto puede declarar variables con este tipo: la siguiente es una statement de variable válida:

 char (*p_array)[]; 

Al igual que un puntero a cualquier otro tipo incompleto, no puede realizar ninguna aritmética de punteros en esta variable (o en su parámetro de función); ahí es donde surge el error. Tenga en cuenta que el operador [] se especifica como a[i] es idéntica a *(a+i) , por lo que ese operador no puede aplicarse a su puntero. Puede, por supuesto, usarlo felizmente como un puntero, así que esto es válido:

 void function(char (*p_array)[]) { printf("p_array = %p\n", (void *)p_array); } 

Este tipo también es compatible con un puntero a cualquier otra matriz de caracteres de tamaño fijo, por lo que también puede hacer esto:

 void function(char (*p_array)[]) { char (*p_a_10)[10] = p_array; puts(*p_a_10); } 

… e incluso esto:

 void function(char (*p_array)[]) { puts(*p_array); } 

(aunque no tiene mucho sentido hacerlo: también puede declarar el parámetro con tipo char * ).

Tenga en cuenta que aunque se permite *p_array , p_array[0] no lo está.

Porque,

 (1) function(char * p_array[]) 

es equivalente a char **p_array ; Es decir, un puntero doble que es válido.

 (2) function(char (*p_array)[]) 

Tienes razón, que p_array es puntero a la matriz de caracteres. Pero eso debe ser de tamaño fijo en el caso cuando aparece como argumento de función. Necesitas proporcionar el tamaño y eso también será válido.

NOTA:
La siguiente respuesta se agregó cuando la Q se etiquetó como C ++ y responde desde una perspectiva de C ++. Con la etiqueta cambiada a solo C, las dos muestras mencionadas son válidas en C.

Sí, tu razonamiento es correcto.
Si intentas comstackr el error dado por el comstackdor es:

 parameter 'p_array' includes pointer to array of unknown bound 'char []' 

En C ++, los tamaños de los arreglos deben fijarse en el momento de la comstackción. El estándar de C ++ prohíbe también la Variable Longht Array (VLA). Algunos comstackdores admiten eso como una extensión, pero eso no es estándar.