Pregunta ¿El doble [] [] no es equivalente a ** doble?


Pregunto esto porque mi programa tiene dos funciones para multiplicar matrices, multiplican solo matrices 4x4 y 4x1. Los encabezados son:

 double** mult4x1(double **m1, double **m2);
 double** mult4x4(double **m1, double **m2);

Hacen m1 * m2 y lo devuelven en ** doble, debajo hay un fragmento de multiplicación 4x4.

 double** mult4x4(double **m1, double **m2){
      double** result = (double**) malloc(sizeof(double)*4);
      for (int i = 0; i < 4; i++) {
           result[i] = (double*) malloc(sizeof(double)*4);
      }
      ...multiply...
      return result;
 }

La diferencia entre mult4x1 y mult4x4 está solo en los índices usados ​​dentro de ellos.

Tengo estas 3 matrices:

double m1[4][4] = {
    {2, 3, 5, 6},
    {9, 8, 1, 7},
    {5, 4, 3, 1},
    {7, 6, 1, 2}
};

double m2[4][4] = {
    {1, 0, 0, 0},
    {0, 1, 0, 0},
    {0, 0, 1, 0},
    {0, 0, 0, 1}
};

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

Al tratar de multiplicar estas matrices, se produce un error.

double** test = mult4x4(m1, m2);
double** test2 = mult4x1(identity4x4(), m3);
//identity4x4() creates a 4x4 identity matrix - double** identity4x4();

Rendimientos:

error: no se puede convertir double (*)[4]' todoble*'por argumento 1' todoble* mult4x4 (doble *doble*) '

error: no se puede convertir double (*)[1]' todoble*'por argumento 2' todoble* mult4x1 (doble *doble*) '

¿No se supone que el doble [] [] es igual a ** el doble? Una matriz de matrices de doble. Cualquier aclaración, concepto erróneo y error son bienvenidos.


34
2017-10-28 14:01


origen


Respuestas:


No.
UN double** es un puntero a un puntero a un doble (double*)

Por lo tanto, en realidad debería crearse así (tenga en cuenta el extra * en el primer malloc sizeof ()):

  double** result = (double**) malloc(sizeof(double*)*4);
  for (int i = 0; i < 4; i++) {
       result[i] = (double*) malloc(sizeof(double)*4);
  }

Entonces en la memoria se vería así:

[] -> { d,d,d,d }
[] -> { d,d,d,d }
[] -> { d,d,d,d }
[] -> { d,d,d,d }

Hay 4 buffers que tienen 4 dobles, pero no son continuos.

Mientras que su doble [4] [4] es un búfer continuo en la memoria, así:

 { { d,d,d,d } { d,d,d,d } {d,d,d,d} {d,d,d,d} }

50
2017-10-28 14:09



Aunque ambos double[N][M] y double** le permiten lidiar con matrices 2D, las dos definitivamente no son equivalentes: la primera representa una matriz 2D de doubles, mientras que el último representa un puntero al puntero al doble, que puede ser interpretado (con la ayuda de la conveniente sintaxis de corchetes cuadrados de C / C ++) como una matriz de punteros para double, o como una matriz de matrices de double.

los double[N][M] representa arreglos 2D de forma "rectangular", mientras que double** le permite crear matrices de "forma libre" (dentada) asignando diferentes cantidades de memoria a cada fila de su matriz.

La diferencia con el compilador es que double[N][M] y un par de enteros {r,c} puede calcular la ubicación del elemento calculando el desplazamiento desde el origen de la matriz, sin leer nada de la memoria. Dado un double**Sin embargo, el compilador debe calcular la dirección del puntero a una fila, leer ese puntero y solo luego calcular la dirección del elemento de destino. Debido a esta diferencia, los dos no son intercambiables.


24
2017-10-28 14:07



No hay ningún tipo [][]. Lo que tienes es de hecho m2 que es una matriz de matrices de tamaño 4 de tipo doble y m1 que es una matriz de matrices de tamaño 1. Una matriz de matrices de tamaño 4 no es equivalente a doble puntero.


3
2017-10-28 14:07



Bueno, espero no ser estúpido aquí, pero la notación double [][] también se usa cuando se dirige a un bloque continuo de memoria, mientras double** no es necesariamente continuo.

Creo que esa es la razón detrás del error. Aunque puede usar la misma semántica para acceder a valores, en realidad son tipos diferentes.


2
2017-10-28 14:09



[] [] no es equivalente a **; double ** var; es un puntero de punteros y, como puede ver en su asignación en la memoria, tiene una matriz de punteros y cada puntero dentro apunta a una matriz de valores de double

double var [4][4];se mantiene en la memoria en su lugar, y es algo equivalente al doble *; En este caso, el conoce el tamaño de la matriz (4 x 4) así que cuando usa var[2][2], por ejemplo, sabe dónde está ubicado eso en la memoria; var[x][y] se traduce a algo como esto: var[x + y * 4] y la declaración puede ser interpretada como double var [16];

Raxvan.


2
2017-10-28 14:10



No... m1 es una matriz con cuatro elementos, cada uno de los cuales es una matriz de cuatro elementos. Lo mismo con m2. Incluso si el primer "nivel" se descompone de una matriz en un puntero, el segundo "nivel" no lo hará. La pregunta es por qué? Veamos un código:

/* double[4][4] implicitly converts to double(*)[4]
 * giving you a pointer to first element of m1 so
 * you get back an array of four doubles.
 */
double (*pm1a)[4] = m1[0];

/* This isn't right, but let's pretend that it was
 * and that what you got back was a pointer
 * to a pointer that pointed to m1 properly.
 */
double **pm1b = (double **)m1[0];

Entonces, ¿qué pasaría con nuestro código hipotético si tuviéramos que hacer pm1a[1] y pm1b[1]?

pm1a[1] está bien: lo haría correctamente avanzar pm1a por 4 * sizeof(double) (dado que el puntero apunta a double[4])

pm1b[1], por otro lado, se rompería: avanzaría por la cantidad incorrecta: el tamaño de un puntero a un doble.

Pero esto no es todo. Todavía hay un error más sutil. Si ambas dimensiones se descompusieran, el compilador no podría saber que una formación se está accediendo Felizmente interpretará pm1b[1] como un puntero a un doble Y luego, ¿qué pasa? Tomará lo que sea double  valor se almacena en ese lugar y lo trata como una puntero a un double.

Puedes ver por qué esto sería un desastre.


2
2017-10-28 14:25



No, no es. double[n][m] asigna un solo bloque de memoria lo suficientemente grande para su matriz bidimensional. A continuación, obtiene la comodidad de no tener que calcular su propia indexación. Al pasar una matriz bidimensional a una función, el compilador requiere que proporcione el tamaño de la dimensión interna para que pueda resolver la indexación.

double** es un puntero a un puntero. Como C permite la aritmética del puntero, puede significar una matriz de punteros, donde cada puntero apunta a una matriz de dobles. Los valores en sí mismos no necesitan residir en un bloque contiguo de memoria. Como puedes ver, son bestias bastante diferentes.

Si tienes un double[n][m] y quiero pasarlo a un double ** necesitarás construir tu propia matriz de indexación.


2
2017-10-28 14:13



Otra diferencia es que no puede doblar para señalar ninguna otra dirección de memoria si la declara como doble [] [] (Algo así como el campo final)

Pero si lo declaras como ** doble, entonces puede señalar cualquier ubicación de memoria.


1
2017-10-28 17:45



No, definitivamente no son equivalentes; el primero representa un conjunto 2D de dobles mientras que el segundo representa un puntero al puntero al doble.


1
2017-10-29 10:05