C ++ Casting doble matriz estática bidimensional para duplicar **

Tengo tal matriz en mi progtwig:

double m[3][4] = { {2, 4, 5, 7}, {4, 5, 1, 12}, {9, 12, 13, -4} }; 

Y me gustaría lanzarlo al double** .

Ya he probado double** a = (double**)m; , pero no funciona (cuando bash leer cualquier valor, aparece “Ubicación de lectura de violación de acceso 0x00000000”, lo que significa que estoy intentando leer desde la dirección NULL .

Encontré una solución casi funcional:

 double *b = &m[0][0]; double **c = &b; 

Funciona cuando leo el campo c[0][any] Pero ocurre el mismo problema de lectura de dirección NULL, cuando bash leer el valor del campo c[1][0] .

¿Cuál es la forma correcta de convertir mi matriz de double m[3][4] para escribir double** ?

Edición: Dices que es imposible. Así que voy a cambiar un poco el problema. ¿Cómo puedo pasar una matriz doble bidimensional como parámetro a una función? Mi función tiene prototipo:

 void calculate(double **matrix, int n); //where matrix size is always n by n+1 

Y está funcionando bien con matrices asignadas dinámicamente. Dudo que la única manera de hacerlo funcionar sea asignando una nueva matriz dinámica y copiando una matriz estática original un elemento por otro …

No puedes simplemente lanzar la matriz. Vas a tener que crear algo como esto:

 double m[3][4] = { {2, 4, 5, 7}, {4, 5, 1, 12}, {9, 12, 13, -4} }; double *marray[3] = {m[0],m[1],m[2]}; calculate(marray,3); 

O puedes usar un bucle:

 const size_t n = 3; double *marray[n]; for (size_t i=0; i!=n; ++i) { marray[i] = m[i]; } calculate(marray,n); 

Usted no puede

La notación double** refiere a una matriz de punteros. No tienes un conjunto de punteros, tienes un conjunto de matrices de dobles.

Cuando escribes

 double m[3][4] { {2, 4, 5, 7}, {4, 5, 1, 12}, {9, 12, 13, -4} }; 

El comstackdor en realidad crea una matriz de dobles como si hubiera escrito

 double _m[] = {2, 4, 5, 7, 4, 5, 1, 12, 9, 12, 13, -4}; 

Sin embargo, gracias al sistema de tipo C / C ++, el comstackdor recuerda que el tipo de m es double [3][4] . En particular recuerda los tamaños 3 y 4.

Cuando escribes

 m[i][j] 

el comstackdor lo reemplaza por

 _m[i * 4 + j]; 

(El 4 viene del segundo tamaño en double [3][4] .) Por ejemplo, m[1][2] == 1 y _m[1 * 4 + 2] == _m[6] == 1 como bien.

Como han dicho otros, un double** es un tipo diferente que no lleva los tamaños con él. Para considerar el double** a como una matriz de 3 x 4, a[0] , a[1] y a[2] deben ser punteros a double (es decir, double* ) que apunta al primer elemento de la fila correspondiente. Puedes lograr esto con

 double* rows[] = { &m[0][0], &m[1][0], &m[2][0] }; double** a = &rows[0]; 

Un reparto simple no crea las rows variables anteriores. Permítanme presentarles otras formas alternativas (pero equivalentes) de definir rows

 double* rows[] = { &m[0][0], &m[0][0] + 4, &m[0][0] + 2 * 4}; double* rows[] = { &_m[0], &_m[4], &_m[2 * 4]}; 

Como puede ver, solo el segundo tamaño (es decir, 4 ) es necesario. En general, para matrices multidimensionales, se requieren todos los tamaños, pero los primeros. Por este motivo una matriz unidimensional.

 double x[4] = { 1, 2, 3, 4 }; 

se puede convertir implícitamente a un double*

 double* y = x; 

Usando este hecho también podemos escribir

 double* rows[] = { _m, _m + 4, _m + 2 * 4}; 

De hecho, _m se convierte en un double* apunta a m[0] . Luego, en _m + 4 , _m se convierte en un double* apuntando a m[0] y a este puntero se agrega 4 . Por lo tanto, _m + 4 es un indicador del cuarto doble siguiente _m[0] , que es _m[4] y así sucesivamente.

Hasta ahora he explicado por qué no puedes lanzar un double [3][4] (o cualquier otro tamaño) a un double** . Ahora, en su caso particular, muestro cómo se puede definir el cálculo.

 template  void calculate(double (&m)[N][N+1]) { // use m as a double[N][N+1] } 

Llama

 calculate(m); 

y el comstackdor deducirá el tamaño N para ti. En general (es decir, cuando la segunda dimensión no es la N + 1 ) puede escribir

 template  void calculate(double (&m)[N][M]) { // use m as a double[N][M] } 

Si siempre está utilizando matrices (sin punteros) para la inicialización, y puede evitar las cosas de puntero en su función de cálculo, podría considerar la siguiente opción, que utiliza la deducción de tamaño por plantillas.

 template void doubleFunc(double (&mat)[m][n]) { for (auto i = 0; i < m; i++) { for (auto j = 0; j < n; j++) { std::cout << mat[i][j] << std::endl; } } } 

Funcionó durante mi prueba rápida.

 double m[3][4] = { {2, 4, 5, 7}, {4, 5, 1, 12}, {9, 12, 13, -4} }; doubleFunc(m); 

Puede pasar una matriz 2d como un parámetro de función:

void calculate(double matrix[][y], int n);

Hasta que las matrices de longitud variable estén en el estándar de C ++, sus opciones incluyen:

  • Si su comstackdor admite matrices de longitud variable como una extensión, es probable que pueda pasarlas con una statement de función como void foo(std::size_t n, double a[][n+1]) . Tenga en cuenta que es probable que el comstackdor requiera que se pase n antes de una statement de parámetro que use n o requiera una syntax especial.
  • Puede pasar un double * y hacer un índice aritmético manualmente en la función: void foo(std::size_t n, double *a) { … a[row*(n+1) + column] … }
  • Puede crear una clase en la que implementa matrices de longitud variable haciendo la aritmética de índice en sus funciones de acceso.
  • Puede asignar espacio para que n punteros se double , rellenar esos punteros con punteros a cada fila de la matriz y pasar la dirección del espacio.