Cómo pasar una matriz multidimensional a una función en C y C ++

#include void print(int *arr[], int s1, int s2) { int i, j; for(i = 0; i<s1; i++) for(j = 0; j<s2; j++) printf("%d, ", *((arr+i)+j)); } int main() { int a[4][4] = {{0}}; print(a,4,4); } 

Esto funciona en C, pero no en C ++.

error:

 cannot convert `int (*)[4]' to `int**' for argument `1' to `void print(int**, int, int)' 

¿Por qué no funciona en C ++? ¿Qué cambio se necesita hacer?

Este código no funcionará en C o C ++. Una matriz de tipo int[4][4] no es convertible a un puntero de tipo int ** (que es lo que int *arr[] representa en la statement de parámetro). Si logró comstackrlo en C, es simplemente porque probablemente ignoró una advertencia del comstackdor C básicamente del mismo formato que el mensaje de error que obtuvo del comstackdor C ++. (A veces los comstackdores C emiten advertencias para lo que es esencialmente un error ).

Entonces, nuevamente, no hagas afirmaciones que no sean verdaderas. Este código no funciona en C. Para convertir una matriz 2D incorporada en un puntero int ** puedes usar una técnica como esta

Conversión de matrices multidimensionales a punteros en c ++

(Consulte la respuesta aceptada. El problema es exactamente el mismo).

EDIT: el código parece funcionar en C porque otro error en el código de impresión está enmascarando los efectos del error en el paso de la matriz. Para acceder correctamente a un elemento de una pseudo-matriz int ** , debe usar la expresión *(*(arr + i) + j) , o mejor una arr[i][j] simple arr[i][j] (que es lo mismo ) Te perdiste el extra * que lo hizo imprimir algo que no tiene absolutamente nada que ver con el contenido de tu matriz. Nuevamente, inicialice su matriz en main a otra cosa para ver que los resultados que está imprimiendo en C no tienen absolutamente nada que ver con el contenido previsto de la matriz.

Si cambia la statement de printf como se muestra arriba, es muy probable que su código falle debido al error de paso de matriz que describí inicialmente.

Una vez más: no se puede pasar una matriz int[4][4] como una pseudo-matriz int ** . Esto es lo que el C ++ le dice en el mensaje de error. Y, estoy seguro, esto es lo que tu comstackdor de C te dijo, pero probablemente lo ignoraste, ya que era “solo una advertencia”.

El problema es ese

 int a[4][4]; 

en realidad se almacenará en una memoria física continua. Por lo tanto, para acceder a una parte arbitraria de su matriz 4×4, la función “imprimir” necesita conocer las dimensiones de la matriz. Por ejemplo, la siguiente pequeña porción de código, accederá a la misma parte de la memoria de dos maneras diferentes.

 #include  void print(int a[][4]){ for (int i = 0; i <4; i++){ for (int j = 0; j < 4; j++){ //accessing as 4x4 array std::cout << a[i][j] < 

Entonces, el diseño de la memoria no cambia, pero la forma de acceder sí lo hace. Se puede visualizar como un tablero de ajedrez.

  0 1 2 3 ---------- 0| 1 2 3 4 1| 5 6 7 8 2| 9 10 11 12 3|13 14 15 16 

Pero la memoria física real se ve así.

 0*4+0 0*4+1 0*4+2 0*4+3 1*4+0 1*4+1 1*4+2 1*4+3 2*4+1 etc. ----------------------------------------------------- 1 2 3 4 5 6 7 8 9 etc. 

En c ++ los datos de una matriz se almacenan fila por fila y la longitud de una fila (en este caso 4) siempre es necesaria para llegar a la compensación de memoria adecuada para la siguiente fila. El primer subíndice, por lo tanto, solo indica la cantidad de almacenamiento que se necesita cuando se declara el conjunto, pero ya no es necesario calcular el desplazamiento después.

 #include void print(int arr[][4], int s1, int s2) { int i, j; printf("\n"); for(i = 0; i 

Esto funcionará, donde por trabajo me refiero a comstackr. @AndreyT explicó por qué tu versión ya no funciona.

Así es como debes pasar una matriz 2d.

Para mayor claridad, también puede especificar ambos tamaños en la statement de la función:

 #include void print(int arr[4][4], int s1, int s2) { int i, j; printf("\n"); for(i = 0; i 

Ambos funcionarán.

También debe cambiar *((arr+i)+j) a a[i][j] (preferiblemente) o *(*(arr+i)+j) si su intención es acceder al elemento j th de la fila i .

Aquí hay una versión que funciona, pero teóricamente no válida (ver abajo) C90 y C ++ 98:

 #include  static void print(int *arr, size_t s1, size_t s2) { size_t i, j; printf("\n"); for(i = 0; i < s1; i++) { for(j = 0; j < s2; j++) { printf("%d, ", arr[i * s2 + j]); } } printf("\n"); } int main(void) { int a[4][4] = {{0}}; print(a[0], 4, 4); return 0; } 

Una versión de C ++ que utiliza plantillas (adaptadas de la respuesta de Notinlist ) podría verse así:

 #include  #include  using namespace std; template  struct IntMatrix { int data[N][M]; IntMatrix() { memset(data, 0, sizeof data); } }; template  ostream& operator< <(ostream& out, const IntMatrix& m) { out < < "\n"; for(size_t i = 0; i < N; i++) { for(size_t j = 0; j < M; j++) { out << m.data[i][j] << ", "; } } out << "\n"; return out; } int main() { IntMatrix<4,4> a; cout < < a; return 0; } 

Alternativamente, podría usar contenedores STL nesteds, es decir, vector< vector > , en lugar de una matriz simple.

Con C99, podrías hacer

 static void print(size_t s1, size_t s2, int arr[s1][s2]) { printf("\n"); for(size_t i = 0; i < s1; i++) { for(size_t j = 0; j < s2; j++) { printf("%d, ", arr[i][j]); } } printf("\n"); } 

y llámalo como

 print(4, 4, a); 

Como Robert señaló en los comentarios, el primer fragmento involucra un comportamiento indefinido. Sin embargo, suponiendo que la aritmética del puntero siempre resultará en un puntero incluso cuando se trate de un comportamiento indefinido (y no explote su computadora), solo hay un único resultado posible debido a otras restricciones dentro del estándar, es decir, este es un caso donde el estándar deja algo innecesariamente indefinido.

Por lo que puedo decir, sustituyendo

 print(a[0], 4, 4); 

con

 union m2f { int multi[4][4]; int flat[16]; } *foo = (union m2f *)&a; print(foo->flat, 4, 4); 

lo hará legal C.

Puede usar int** lugar. Es mucho más flexible:

 #include  #include  void print(int **a, int numRows, int numCols ) { int row, col ; for( int row = 0; row < numRows; row++ ) { for( int col = 0; col < numCols ; col++ ) { printf("%5d, ", a[row][col]); } puts(""); } } int main() { int numRows = 16 ; int numCols = 5 ; int **a ; // a will be a 2d array with numRows rows and numCols cols // allocate an "array of arrays" of int a = (int**)malloc( numRows* sizeof(int*) ) ; // each entry in the array of arrays of int // isn't allocated yet, so allocate it for( int row = 0 ; row < numRows ; row++ ) { // Allocate an array of int's, at each // entry in the "array of arrays" a[row] = (int*)malloc( numCols*sizeof(int) ) ; } int count = 1 ; for( int row = 0 ; row < numRows ; row++ ) { for( int col = 0 ; col < numCols ; col++ ) { a[row][col] = count++ ; } } print( a, numRows, numCols ); } 

Otra cosa que puede interesarle es una estructura como D3DMATRIX :

 typedef struct _D3DMATRIX {
     Unión {
         struct {
             float _11, _12, _13, _14;
             float _21, _22, _23, _24;
             float _31, _32, _33, _34;
             flotador _41, _42, _43, _44;

         };
         flotar m [4] [4];
     };
 } D3DMATRIX;

 D3DMATRIX myMatrix;

Lo bueno de este pequeño tidbit es que puedes usar myMatrix.m[0][0] (para acceder al primer elemento), o puedes usar myMatrix._11 para acceder también al mismo elemento. La unión es el secreto.

 #include template  struct DataHolder { int data[N][M]; DataHolder() { for(int i=0; i void print(const DataHolder& dataHolder) { printf("\n"); for(int i = 0; i a; print(a); } 

Además de utilizar matrices de longitud variable en C99, no se puede escribir de manera portátil una función para aceptar una matriz multidimensional si no se conocen los tamaños de las matrices en tiempo de comstackción, consulte la Pregunta 6.19 de C-FAQ . La mejor forma de manejar esto es simular matrices multidimensionales utilizando memoria asignada dinámicamente. La pregunta 6.16 hace un muy buen trabajo explicando los detalles de hacer esto.

Respuesta corta, puede cambiar el progtwig de la siguiente manera

 void print(int arr[], int s1, int s2) { ... printf("%d,", *(a+i + s2*j)); ... print((int*)a,4,4); 

Esto necesitaría una mejor respuesta para explicar las diferencias entre la aritmética y las matrices de puntero y puntero en C y C ++. No me lanzaré a eso ahora. ¿Tal vez alguien más?

Obviamente, no estoy sorprendido por el mismo punto que otros carteles en su código. Lo que más me molesta en el encabezado de la función de impresión es que utiliza una indirección doble para una matriz en la que no tiene la intención de cambiar el puntero inicial (de hecho, no se puede hacer ya que es una constante). @ | V | lad answer corrige esto estableciendo una o dos dimensiones en una constante fija, pero luego pasar s1 y s2 se vuelve inútil.

Todo depende de lo que realmente quieras hacer. ¿Imprimir es una función de impresión de matriz de propósito general o una especializada para algunos tipos de matriz?

Lo primero que debe hacer es obtener los tipos correctos. Si las reglas de C ++ son las mismas que las de C con respecto a los tipos de arreglo (estoy bastante seguro de que lo son), entonces, dada la statement

 int a[4][4]; 

la expresión a tiene tipo int [4][4] , que se convierte implícitamente (“decae”) a un tipo de puntero de int (*)[4] (puntero a matriz de 4 elementos de int) cuando se pasa a print , por lo necesitas cambiar la print a

 void print(int (*arr)[4], int s1, int s2) { int i, j; for(i = 0; i 

La expresión arr[i] elimina las referencias de forma implícita, por lo que no necesita meterse con una desreferencia explícita.

El inconveniente es que la print solo puede manejar matrices Nx4 de int; si desea manejar otros tamaños de matriz, deberá adoptar un enfoque diferente.

Una cosa que puede hacer es en lugar de pasar la matriz, pasar la dirección del primer elemento y hacer que la print calcule manualmente los desplazamientos, de la siguiente manera:

 int main() { int a[4][4] = {{0}}; print(&a[0][0],4,4); // note how a is being passed } void print(int *arr, int s1, int s2) // note that arr is a simple int * { int i, j; for (i = 0; i < s1; i++) for (j = 0; j < s2; j++) printf("%d, ", arr[i * s2 + j]); } 

Las matrices multidimensionales son bloques continuos de memoria. Entonces puedes hacerlo de esta manera:

 #include  void pa(const int *a, int y, int x) { int i, j; for (i=0;i 

También funciona en C ++;

Solo quiero mostrar la versión en C ++ de la respuesta de bobobobo.

 int numRows = 16 ; int numCols = 5 ; int **a ; a = new int*[ numRows* sizeof(int*) ]; for( int row = 0 ; row < numRows ; row++ ) { a[row] = new int[ numCols*sizeof(int) ]; } 

El rest del código es lo mismo con bobobobo's.

 #include void print(int (*arr)[4], int s1, int s2) { int i, j; for(i = 0; i 

esto comstackrá editar: alguien ya publicó esta solución mi mala