2012-08-08 10 views
12

Tengo una función que toma un puntero a una matriz de coma flotante. En base a otras condiciones, sé que el puntero apunta a una matriz 2x2 O 3x3. (de hecho, la memoria se asignó inicialmente como tal, por ejemplo, float M [2] [2]) Lo importante es que quiero hacer esta determinación en el cuerpo de la función, no como el argumento de la función.Cómo lanzar un puntero simple a una matriz multidimensional de tamaño fijo?

void calcMatrix(int face, float * matrixReturnAsArray) 
{ 
    // Here, I would much rather work in natural matrix notation 
    if(is2x2) 
    { 
     // ### cast matrixReturnAsArray to somethingAsMatrix[2][2] 
     somethingAsMatrix[0][1] = 2.002; 
     // etc.. 
    } 
    else if(is3x3) 
    { //etc... 
    } 

} 

Soy consciente de que podría utilizar plantillas y otras técnicas para abordar mejor este problema. Mi pregunta es realmente acerca de cómo hacer un molde de este tipo en el comentario ###. Trabajando en C++.

+2

Creo que estás tratando de resolver el problema incorrecto (es decir, "¿cómo moldear?" es * rara vez * el problema correcto). Escribí una solución simple al problema de "cómo usar matrices multidimensionales fácilmente". una vez: http://ideone.com/gytw7 –

+0

No hay forma de que un 'float *' apunte a un * todo * multidimensional (salvo que el casting realmente terrible no debería estarlo y me sorprendería si un compilador lo dejara tú). Un 'float *' apunta a un flotante, que puede ser el primer valor en una matriz de flotación de una sola dimensión. Pero no apunta a ninguna sub-matriz, como lo necesitaría para una matriz multidimensional. 2x2 y 3x3 son ambos 2D, por lo que ambos podrían ser 'float **'. Realmente, sin embargo, sería mucho mejor crear (o encontrar) y usar una clase 'Matrix' dedicada. – KRyan

+0

Ok, podría cambiar mi argumento de entrada para flotar **.¿Pero estás diciendo que en el caso de float aMDarray [3] [3], no se garantiza que el almacenamiento de elementos sea continuo? – NoahR

Respuesta

20
float (*somethingAsMatrix)[2] = (float (*)[2]) matrixReturnAsArray; 
+0

Gracias. Esto ciertamente funciona ahora. Solo estoy aclarando si tengo un concepto erróneo sobre la disposición contigua garantizada de los elementos en el caso de declaración float aMDarray [3] [3]; – NoahR

+1

@NoahR: Es contiguo y compatible con el uso que sugiera. –

+0

Probé esta técnica y el compilador Mac OS X C++ dijo 'error: asignando a 'double (*) [LDN]' desde el tipo incompatible 'double (*) [LDN]' '. ¡Observe que los dos tipos reportados son iguales! Entonces, ¿por qué no son asignables? Mi código se ve así 'doble (* F) [LDN]; F = (double (*) [LDN]) AF; 'También intenté inicializar en la declaración y recibí un mensaje de error similar. – Jason

1

Este tipo de fundición es siempre más limpio y más fácil de manejar, con un uso juicioso de typedef:

typedef float Matrix_t[2][2]; 

Matrix_t* someThingAsMatrix = (Matrix_t*) matrixReturnAsArray; 

Si esto es C++ y no en C, sin embargo, se debe crear una matriz clase. (O mejor aún, busque uno de código abierto.)

+1

Use someThingAsMatrix [1] [1] = 2.0f; da: Tipos incompatibles en la asignación de 'float' a 'float [2]' – NoahR

+2

Typedef sigue siendo útil, pero necesita: 'typedef float MatrixRow [2]; MatrixRow * someThingAsMatrix = (MatrixRow *) matrixReturnAsArray; 'que es equivalente a la respuesta de ecatmur. –

4

float * podría apuntar al primer elemento de una matriz de flotantes, y debería reinterpretarse_castable a ese tipo de matriz. Y el resultado de ese lanzamiento podría apuntar al primer elemento de un float [][] y, por lo tanto, debería reinterpretarse_castable a ese tipo, y así sucesivamente. Usted debe ser capaz de componer dichos moldes y apenas lo hacen directamente

float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(matrixReturnAsArray); 

Un argumento de tipo float ** no es lo mismo y no se debe utilizar de esta manera.

Para evitar un comportamiento indefinido, el puntero debe proceder de una matriz multidimensional real, y si se usa directamente el float*, no podrá acceder a más de la primera fila de la matriz multidimensional.

void foo(float *f) { 
    f[3] = 10.; 

    float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(f); 
    arr[1][1] = 10.; 
} 

void main() { 
    float a[2][2]; 
    foo(&a[0][0]); // f[3] = 10.; is undefined behavior, arr[1][1] = 10. is well defined 

    float b[4]; 
    foo(&b[0]); // f[3] = 10.; is well-defined behavior, arr[1][1] = 10. is undefined 
} 

Dada float arr[2][2]; nada garantiza que &arr[0][1] + 1 es lo mismo que &arr[1][0], por lo que yo he podido determinar. Por lo tanto, aunque puede usar una matriz dimensional única como matriz multidimensional al hacer f[i*width + j], no puede tratar una matriz multidimensional como una matriz dimensional única.

Es mejor utilizar la seguridad de tipo de tiempo de compilación de C++ en lugar de simplemente confiar en que no se pase el error por error o que se realice la reinterpretación_cast incorrecta. Para obtener seguridad de tipos usando primas-arrays se debe utilizar referencias al tipo de matriz prima que desee:

void foo(float (&f)[2][2]) {} 
void foo(float (&f)[3][3]) {} 

Si desea pasar matrices de valor que no se puede utilizar matrices primas y en su lugar debe usar algo como std :: arreglo:

void foo(std::array<std::array<float,2>,2> f) {} 
void foo(std::array<std::array<float,3>,3> f) {} 
+1

¿No está garantizado que 'sizeof (T [N])' sea exactamente 'N * sizeof (T)'? –

+1

Conozco una nota no normativa en el estándar que menciona eso. Si puede encontrar algo normativo, hágamelo saber. – bames53

+1

5.3.3p2 indica directamente que es obligatorio. Parece normativo para mí (no dentro de una "Nota") –

Cuestiones relacionadas