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

Tengo un progtwig que se parece a lo siguiente:

double[4][4] startMatrix; double[4][4] inverseMatrix; initialize(startMatrix) //this puts the information I want in startMatrix 

Ahora quiero calcular el inverso de startMatrix y ponerlo en inverseMatrix. Tengo una función de biblioteca para este propósito cuyo prototipo es el siguiente:

 void MatrixInversion(double** A, int order, double** B) 

eso toma el inverso de A y lo coloca en B. El problema es que necesito saber cómo convertir el doble [4] [4] en un doble ** para darle a la función. Intenté simplemente hacerlo de la “manera obvia”:

 MatrixInversion((double**)startMatrix, 4, (double**)inverseMatrix)) 

pero eso no parece funcionar. ¿Es esa la forma correcta de hacerlo?

No, no hay una forma correcta de hacerlo específicamente. Una matriz double[4][4] no es convertible a un double ** puntero. Estas son dos maneras alternativas e incompatibles de implementar una matriz 2D. Algo necesita ser cambiado: ya sea la interfaz de la función o la estructura de la matriz pasada como un argumento.

La forma más simple de hacer esto último, es decir, hacer que su matriz existente double[4][4] compatible con la función, es crear matrices “indexadas” temporales de tipo double *[4] apuntando al comienzo de cada fila en cada una matriz

 double *startRows[4] = { startMatrix[0], startMatrix[1], startMatrix[2] , startMatrix[3] }; double *inverseRows[4] = { /* same thing here */ }; 

y pasar estas matrices de “índice” en su lugar

 MatrixInversion(startRows, 4, inverseRows); 

Una vez que la función haya finalizado, puede olvidarse de las matrices startRows e inverseRows , ya que el resultado se colocará correctamente en su matriz inverseMatrix original.

Por una razón dada que la matriz bidimensional (un bloque contiguo de memoria) y una matriz de punteros (no contiguos) son cosas muy diferentes, no se puede pasar una matriz bidimensional a una función que funcione con puntero a puntero.

Una cosa que podrías hacer: plantillas. Haga que el tamaño de la segunda dimensión sea un parámetro de plantilla.

 #include  template  void print(double a[][N], unsigned order) { for (unsigned y = 0; y < order; ++y) { for (unsigned x = 0; x < N; ++x) { std::cout << a[y][x] << ' '; } std::cout << '\n'; } } int main() { double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}}; print(arr, 3); } 

Otra manera, un poco más torpe, podría ser hacer que la función acepte un puntero a una matriz de una dimensión, y tanto el ancho como la altura proporcionados como argumentos, y calcular los índices en una representación bidimensional usted mismo.

 #include  void print(double *a, unsigned height, unsigned width) { for (unsigned y = 0; y < height; ++y) { for (unsigned x = 0; x < width; ++x) { std::cout << a[y * width + x] << ' '; } std::cout << '\n'; } } int main() { double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}}; print(&arr[0][0], 3, 3); } 

Naturalmente, una matriz es algo que merece una clase propia (pero lo anterior aún podría ser relevante, si necesita escribir funciones auxiliares).

Como está utilizando C ++, la forma correcta de hacer algo como esto sería con una clase personalizada y algunas plantillas. El siguiente ejemplo es bastante difícil, pero tiene el punto básico.

 #include  using namespace std; template  class SquareMatrix { public: int size(void) { return matrix_size; } double array[matrix_size][matrix_size]; void copyInverse(const SquareMatrix & src); void print(void); }; template  void SquareMatrix::copyInverse(const SquareMatrix & src) { int inv_x; int inv_y; for (int x = 0; x < matrix_size; x++) { inv_x = matrix_size - 1 - x; for (int y = 0; y < matrix_size; y++) { inv_y = matrix_size - 1 - y; array[x][y] = src.array[inv_x][inv_y]; } } } template  void SquareMatrix::print(void) { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { cout << array[x][y] << " "; } cout << endl; } } template  void Initialize(SquareMatrix & matrix); int main(int argc, char * argList[]) { SquareMatrix<4> startMatrix; SquareMatrix<4> inverseMatrix; Initialize(startMatrix); inverseMatrix.copyInverse(startMatrix); cout < < "Start:" << endl; startMatrix.print(); cout << "Inverse:" << endl; inverseMatrix.print(); return 0; } template  void Initialize(SquareMatrix & matrix) { for (int x = 0; x < matrix_size; x++) { for (int y = 0; y < matrix_size; y++) { matrix.array[x][y] = (x+1)*10+(y+1); } } } 

La matriz bidimensional no es un puntero a puntero o algo similar. El tipo correcto para startMatrix es double (*)[4] . Para su función, la firma debería ser como:

 MatrixInversion( double (*A)[4], int order, double (*B)[4] ); 

Hay una solución que usa el puntero para señalar por bobobobo

William Sherif (bobobobo) usó la versión C y 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.

El problema es que una matriz bidimensional no es lo mismo que una matriz de punteros. Una matriz bidimensional almacena los elementos una fila tras otra, por lo tanto, cuando pasa una matriz de este tipo, solo se proporciona un puntero al inicio. La función de recepción puede encontrar la forma de encontrar cualquier elemento de la matriz, pero solo si conoce la longitud de cada fila .

Por lo tanto, su función de recepción debe declararse void MatrixInversion(double A[4][], int order, double B[4][]) .

por buena encoding si c ++:

 struct matrix { double m[4][4]; }; matrix startMatrix; matrix inverseMatrix; 

entonces la interfaz sería

 void MatrixInversion(matrix &A, int order, matrix &B); 

y usarlo

 MatrixInversion(startMatrix, 4, inverseMatrix); 

El beneficio

  1. la interfaz es muy simple y clara.
  2. una vez que necesite modificar “m” de la matriz internamente, no necesita actualizar la interfaz.

O de esta manera

 struct matrix { void Inversion(matrix &inv, int order) {...} protected: double m[4][4]; }; matrix startMatrix; matrix inverseMatrix; ... 

Una forma fea en c

 void MatrixInversion(void *A, int order, void *B); MatrixInversion((void*)startMatrix, 4, (void*)inverseMatrix); 

EDITAR: código de referencia para MatrixInversion que no se bloqueará:

 void MatrixInversion(void *A, int order, void *B) { double _a[4][4]; double _b[4][4]; memcpy(_a, A, sizeof _a); memcpy(_b, B, sizeof _b); // processing data here // copy back after done memcpy(B, _b, sizeof _b); }