2012-08-08 15 views
12

Mam funkcję, która pobiera wskaźnik do tablicy zmiennoprzecinkowej. Na podstawie innych warunków wiem, że wskaźnik wskazuje na matrycę 2x2 OR 3x3. (w rzeczywistości pamięć została początkowo przydzielona jako taka, np. float M [2] [2]). Ważne jest, że chcę to ustalenie w treści funkcji, a nie jako argument funkcji.Jak przesłać prosty wskaźnik do wielowymiarowej tablicy o stałym rozmiarze?

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... 
    } 

} 

Jestem świadomy, że mogę użyć szablonów i innych technik, aby lepiej rozwiązać ten problem. Moje pytanie dotyczy tego, jak zrobić taką obsadę w komentarzu ###. Praca w C++.

+2

Myślę, że próbujesz rozwiązać niewłaściwy problem (np. "jak rzutować?" jest * rzadko * właściwym problemem). Napisałem proste rozwiązanie problemu "jak używać tablic wielowymiarowych w prosty sposób?" once: http://ideone.com/gytw7 –

+0

Nie ma sposobu, żeby "float *" wskazywał na wielowymiarowy * cokolwiek * (z wyjątkiem naprawdę okropnego rzucania, którego nie powinieneś robić) i byłbym zaskoczony, gdyby kompilator ty). Wartość 'float * 'wskazuje na zmienną, która może być pierwszą wartością w jednowymiarowej macierzy zmiennoprzecinkowej. Ale nie wskazuje żadnej pod-tablicy, jak byś potrzebował do wielowymiarowej tablicy. 2x2 i 3x3 są zarówno 2D, więc oba mogą być 'float **'. Naprawdę, znacznie lepiej byłoby stworzyć (lub znaleźć) i użyć dedykowanej klasy 'Matrix'. – KRyan

+0

Ok, mógłbym zmienić mój argument wejściowy na float **.Ale czy mówisz, że w przypadku pływaka aMDarray [3] [3], przechowywanie pierwiastków nie gwarantuje ciągłości? – NoahR

Odpowiedz

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

Dziękuję. To na pewno działa teraz. Po prostu wyjaśniam, czy mam błędne przekonanie na temat gwarantowanego, ciągłego układania elementów w przypadku deklaracji float aMDarray [3] [3]; – NoahR

+1

@NoahR: To jest ciągłe i zgodne z sugerowanym użyciem. –

+0

Próbowałem tej techniki, a kompilator Mac OS X C++ powiedział: "error: assigning to" double (*) [LDN] "z niekompatybilnego typu 'double (*) [LDN]''. Zauważ, że oba zgłoszone typy są takie same! Dlaczego więc nie można ich przypisać? Mój kod wygląda tak: 'double (* F) [LDN]; F = (double (*) [LDN]) AF; 'Próbowałem również zainicjować w deklaracji i otrzymałem podobny komunikat o błędzie. – Jason

1

Ten rodzaj odlewu jest zawsze czystsze i łatwiejsze do czynienia, z rozsądnego korzystania z typedef:

typedef float Matrix_t[2][2]; 

Matrix_t* someThingAsMatrix = (Matrix_t*) matrixReturnAsArray; 

Jeśli jest to C++ i nie C, choć należy utworzyć macierz klasa. (Albo jeszcze lepiej, poszukaj otwartego źródła).

+1

Użyj someThingAsMatrix [1] [1] = 2.0f; daje: Niezgodne typy w przypisaniu "float" do "float [2] ' – NoahR

+2

Typedef jest nadal pomocny, ale potrzebujesz:' typedef float MatrixRow [2]; MatrixRow * someThingAsMatrix = (MatrixRow *) matrixReturnAsArray; 'który jest odpowiednikiem odpowiedzi ecatmur. –

4

float * może wskazywać na pierwszy element tablicy zmiennych, i powinien być reinterpret_castable do tego typu tablicy. Wynik tego odlewu może wskazywać na pierwszy element z float [][], a więc powinien być reinterpret_castable do tego typu, i tak dalej. Powinieneś być w stanie tworzyć takie odlewy i tylko bezpośrednio zrobić

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

Argument typu float ** nie jest taka sama i nie powinny być używane w ten sposób.

Aby uniknąć niezdefiniowanych zachowań, wskaźnik musi pochodzić z rzeczywistej tablicy wielowymiarowej, a jeśli użyty zostanie kod float*, nie można uzyskać dostępu do więcej niż pierwszego wiersza wielowymiarowej macierzy.

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 
} 

Biorąc float arr[2][2]; nic nie gwarantuje, że &arr[0][1] + 1 jest taka sama jak &arr[1][0], o ile udało mi się ustalić. Więc chociaż można użyć tablicy jednowymiarowej jako wielowymiarowej tablicy, wykonując f[i*width + j], nie można traktować wielowymiarowej tablicy, takiej jak jednowymiarowa tablica.

Lepiej używać C++ podczas kompilacji, zamiast polegać tylko na niezamierzonym przekazaniu niewłaściwej rzeczy lub wykonaniu niewłaściwej reinterpret_cast. Aby uzyskać typu bezpieczeństwo korzystania RAW tablic należy użyć odwołania do surowej typu array chcesz:

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

Jeśli chcesz przechodzić przez tablice wartości nie można używać surowych tablic i powinny zamiast użyć coś jak std :: array:

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

Czy "sizeof (T [N])" nie gwarantuje dokładnie "N * sizeof (T)"? –

+1

Jestem świadomy nienormatywnej uwagi w standardzie, która wspomina o tym. Jeśli znajdziesz coś normatywnego, daj mi znać. – bames53

+1

5.3.3p2 bezpośrednio stwierdza, że ​​jest to wymagane. Wygląda normalnie dla mnie (nie wewnątrz "Note") –

Powiązane problemy