¿Por qué tenemos que especificar el tamaño de columna al pasar una matriz 2D como parámetro?

¿Por qué mi parámetro no puede ser

void example(int Array[][]){ /*statements*/} 

¿Por qué debo especificar el tamaño de la columna de la matriz? Diga por ejemplo, 3

 void example(int Array[][3]){/*statements*/} 

Mi profesor dijo que era obligatorio, pero yo estaba codificando antes de que comenzara la escuela y recordé que no había ningún error sintáctico o semántico cuando hice de este mi parámetro. ¿O me perdí algo?

Cuando se trata de describir parámetros, las matrices siempre se descomponen en punteros a su primer elemento.

Cuando pasa una matriz declarada como int Array[3] a la función void foo(int array[]) , se desintegra en un puntero al comienzo de la matriz, es decir, int *Array; . Por cierto, puedes describir un parámetro como int array[3] o int array[6] o incluso int *array : todos estos serán equivalentes y puedes pasar cualquier matriz de enteros sin problemas.

En el caso de las matrices de matrices (matrices 2D), se desintegra a un puntero a su primer elemento, que pasa a ser una única matriz dimensional, es decir, obtenemos int (*Array)[3] .

Especificar el tamaño aquí es importante. Si no fuera obligatorio, no habrá ninguna forma para que el comstackdor sepa cómo tratar con la Array[2][1] expresiones Array[2][1] , por ejemplo.

Para eliminar la referencia de que un comstackdor necesita calcular el desplazamiento del elemento que necesitamos en un bloque contiguo de memoria ( int Array[2][3] es un bloque contiguo de enteros), lo que debería ser fácil para los punteros. Si a es un puntero, entonces a[N] se expande como start_address_in_a + N * size_of_item_being_pointed_by_a . En el caso de la Array[2][1] de expresión Array[2][1] dentro de una función (queremos acceder a este elemento) la Array es un puntero a una única matriz dimensional y se aplica la misma fórmula. La cantidad de bytes en el último corchete es necesaria para encontrar size_of_item_being_pointed_by_a . Si solo tuviéramos Array[][] , sería imposible encontrarlo y, por lo tanto, sería imposible desreferenciar un elemento de matriz que necesitamos.

Sin el tamaño, los aritméticos de punteros no funcionarían para matrices de matrices. ¿Qué dirección produciría Array + 2 : avanzar la dirección en Array 2 bytes adelante (incorrecto) o avanzar el puntero 3* sizeof(int) * 2 bytes adelante?

En C / C ++, incluso las matrices en 2-D se almacenan secuencialmente, una fila tras otra en la memoria. Entonces, cuando tienes (en una sola función):

 int a[5][3]; int *head; head = &a[0][0]; a[2][1] = 2; // <-- 

El elemento al que está accediendo con a[2][1] es *(head + 2*3 + 1) , causa que secuencialmente, ese elemento está después de 3 elementos de la fila 0 y 3 elementos de la fila 1 , y luego un índice más más.

Si declaras una función como:

 void some_function(int array[][]) {...} 

sintácticamente, no debería ser un error. Pero, cuando intenta acceder a la array[2][3] ahora, no puede decir a qué elemento se debe acceder. Por otro lado, cuando tienes:

 void some_function(int array[][5]) {...} 

usted sabe que con el array[2][3] , se puede determinar que realmente está accediendo al elemento en la dirección de memoria *(&array[0][0] + 2*5 + 3) porque la función conoce el tamaño del segunda dimensión

Hay otra opción, como se sugirió anteriormente, puede declarar una función como:

 void some_function(int *array, int cols) { ... } 

porque de esta manera, está llamando a la función con la misma "información" que antes: el número de columnas. Accedes a los elementos de la matriz de una forma un poco diferente a continuación: tienes que escribir *(array + i*cols + j) donde normalmente escribirías array[i][j] , porque array ahora es un puntero a entero (no a un puntero) )

Cuando declara una función como esta, debe tener cuidado de llamarla con el número de columnas que están realmente declaradas para la matriz, no solo utilizadas. Así por ejemplo:

 int main(){ int a[5][5]; int i, j; for (i = 0; i < 3; ++i){ for (int j=0; j < 3; ++j){ scanf("%d", &a[i][j]); } } some_function(&a[i][j], 5); // <- correct some_function(&a[i][j], 3); // <- wrong return 0; } 

Hay una publicación similar con respecto a esto. Puede consultar el siguiente enlace. Crear una matriz en C y pasar el puntero a dicha matriz para funcionar Espero que ayude.

Por otro lado, el comstackdor necesita la segunda dimensión para poder mover “Array” de un puntero al próximo, ya que toda la memoria se organiza de forma lineal.

Cuando creas una matriz 2D, de anytype a[3][4] , en la memoria lo que realmente creas son 3 bloques contiguos de 4 objetos de cualquier tipo.

a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]

Ahora la siguiente pregunta es, ¿por qué es así? Porque, manteniendo las especificaciones y la estructura del lenguaje, anytype a[3][4] realidad se expande en anytype (*a)[4] , porque las matrices se degradan en punteros. Y, de hecho, eso también se expande en anytype (*(*a)) , sin embargo, ahora ha perdido completamente el tamaño de la matriz 2D. Entonces, debes ayudar al comstackdor un poco.

Si solicita al progtwig a[2] , el progtwig puede seguir exactamente los mismos pasos que para los arrays 1D. Simplemente puede devolver the 3rd element of sizeof(object pointed to) , el objeto apuntado aquí es de tamaño 4 de cualquier tipo de objetos.

Todo tiene que ver con la representación de matriz interna. Así que array como int arr_2 [2][2] = {{1,2},{3,4}}; se ve en la memoria como 1,2,3,4 siendo cada uno de tipo entero. arr_2 es más o menos equivalente a &arr[0][0] (puntero al primer elemento) cuando se pasa a una función.

Las matrices usuales se almacenan y se accede de manera similar int arr[2] = {2,5}; en la memoria 2,5 . El comstackdor los obtiene a través de su base más los tiempos de compensación tipo tipo base_ptr + index * type . Para obtener el valor almacenado en el índice 1 de tipo int escribimos &arr[0] + 1 * sizeof(int) = 5

De modo que se accede a dos matrices dimensionales como base_ptr + type * 2nd_dem_len + index . Para obtener el valor almacenado en [1] [1], escribimos &arr_2[0][0] + sizeof(int) * 1 + 1 = 4

Entonces, si el comstackdor no conoce 2nd_dem_len o la longitud de la segunda dimensión, no puede acceder a esa matriz. No lo sabe porque la matriz se diluye en esa representación cuando se pasa a la función porque el comstackdor la convierte en un puntero que no tiene información sobre el tamaño.

En realidad, ya sea una matriz 2d o una matriz 1d, se almacena en la memoria en una sola línea. Para decir el comstackdor, ¿dónde debería romperse la fila que indica los próximos números que se encontrarán en las filas siguientes? tamaño de columna Y romper las filas apropiadamente dará el tamaño de las filas.

Veamos un ejemplo:

 int a[][3]={ 1,2,3,4,5,6,7,8,9,0 }; 

Esta matriz a se almacena en la memoria como:

  1 2 3 4 5 6 7 8 9 0 

Pero como hemos especificado el tamaño de columna como 3, la memoria se divide después de cada 3 números.

 #include int main() { int a[][3]={1,2,3,4,5,6},i,j; for(i=0;i<2;i++) { for(j=0;j<3;j++) { printf("%d ",a[i][j]); } printf("\n"); } } 

SALIDA:

  1 2 3 4 5 6 

En el otro caso,

 int a[3][]={1,2,3,4,5,6,7,8,9,0}; 

El comstackdor solo sabe que hay 3 filas, pero no sabe la cantidad de elementos en cada fila, por lo que no puede asignar memoria y mostrará un error.

 #include int main() { int a[3][]={1,2,3,4,5,6},i,j; for(i=0;i<3;i++) { for(j=0;j<2;j++) { printf("%d ",a[i][j]); } printf("\n"); } } 

SALIDA:

  c: In function 'main': c:4:8: error: array type has incomplete element type 'int[]' int a[3][]={1,2,3,4,5,6},i,j; ^