2009-08-16 10 views
2

Ich habe eine Funktion, die einen Zeiger auf einen Zeiger als Argument verwendet.2D-Arrays mit C++

func(double **arr, int i); 

wo in der Hauptfunktion das Array wie folgt definiert ist:

double arr[][] = //some initialization here; 

Wie kann ich diese Funktion von meinem Haupt-Code aufrufen. Ich habe Folgendes versucht, aber es gibt einen Fehler

func (&arr); 

Funktioniert nicht. Jede Hilfe würde sehr geschätzt werden. Dank

Antwort

10

Ein double **p ist nicht das gleiche wie ein double[][] a, so dass Sie nicht eins als das andere übergeben können.

Insbesondere ist die zweidimensionale Arrayvariable ein (einzelner!) Speicherblock mit Doppelpunkten, auf den Sie mit der Syntax [][] zugreifen können. Diese erfordert, dass der Compiler die Dimension des Arrays kennen, so dass es den richtigen Offset für jedes Element berechnen kann. Es kann auch transparent zu einem Zeiger auf diesen Speicherblock zerfallen, aber dabei verliert man das Verständnis, wie man auf diesen Speicher als ein zweidimensionales Array zugreift: Es wird effektiv ein Zeiger zum Doppelten.

+----+   +---------+---------+---------+ 
| (a---------->) | a[0][0] | a[0][1] | a[0][2] | ... 
+----+   +---------+---------+---------+ 
       | a[1][0] | a[1][2] | ... 
       +---------+---------+ 
        ... 

Das, was von der Funktion zu erwarten ist ein Zeiger auf einen Speicherblock die zusätzlichen Speicherblöcke enthält, verdoppelt einen oder mehrere Zeiger enthält.

+---+  +------+  +---------+---------+ 
| p-------->| p[0]------->| p[0][0] | p[0][3] | ... 
+---+  +------+  +---------+---------+ 
      | p[1]--\  
      +------+ \ +---------+---------+ 
      ...  --->| p[1][0] | p[1][4] | ... 
          +---------+---------+ 

Während die Syntax ähnlich aussieht, haben diese beiden Strukturen eine völlig andere Semantik.


Für eine vollständigere Diskussion siehe my answer zu einem previous questions (die c tatsächlich ansprechen, aber die Probleme sind die gleichen).

+0

also wie übertrage ich das Array zu meinem func? Ich bin verwirrt. Ich möchte es an func weitergeben, ohne seine Erklärung zu ändern. – zack

16

Die Art der arr ist double[X][Y] - das heißt, verdoppelt sich eine Reihe von X-Arrays von Y - wo X und Y auf initializers abhängen. Dies ist nicht das gleiche wie Zeigertyp. Gemäß den C-Konvertierungsregeln kann ein Array jedoch in einen Zeiger auf sein Element zerfallen. In Ihrem Fall ist der Typ, der aus einem solchen Zerfall resultiert, doppelt (*) [Y] - ein Zeiger auf eine Anordnung von Y-Doppelpunkten. Beachten Sie, dass dies ein Zeiger auf Array ist, kein Array von Zeigern, so wird es nicht weiter zerfallen. An diesem Punkt erhalten Sie einen Typenkonflikt, da Ihre Funktion double** erwartet.

Der richtige Weg, dies zu behandeln, ist, das Array als eindimensional zu behandeln und Breite entlang zu führen. Also:

void func(double* arr, int w) { 
    // arr[2][3] 
    arr[2*w + 3] = ...; 
} 


double x[6][8] = { ... }; 
func(&x[0][0], 8); 

In C++ insbesondere, wenn Sie immer statisch Arrays von bekannten (aber verschiedenen) Arten zugeordnet haben, können Sie in der Lage sein, Vorlagen zu verwenden und Referenzen wie folgt aus:

template <int W, int H> 
inline void func(const double (&arr)[W][H]) { 
    arr[2][3] = ...; 
} 

double x[6][8] = { ... }; 
func(x); // W and H are deduced automatically 

Dies funktioniert jedoch nicht, wenn Sie nur einen Zeiger haben (zB wenn das Array new -allocated ist und seine Größe zur Laufzeit berechnet wird).Für den allgemeinsten Fall sollten Sie stattdessen C++ - Container verwenden. Mit nur Standard-Bibliothek, verwendet man in der Regel Vektor von Vektoren:

#include <vector> 

void func(std::vector<std::vector<double> > arr) { 
    arr[2][3] = ...; 
} 

std::vector<std::vector<double> > x(6, std::vector<double>(8)); 
x[0][0] = ...; 
... 
func(x); 

Wenn Sie Boost-verwenden können, muss es eine sehr schöne Multiarray-Bibliothek in ihm:

void func(boost::multi_array<double, 2> arr) { // 2 means "2-dimensional" 
    arr[2][3] = ...; 
} 

boost::multi_array<double, 2> x(boost::extents[6][8]); 
x[0][0] = ...; 
... 
func(x); 

[EDIT] Sie sagen, dass Sie können die Definition Ihrer Funktion nicht ändern. Wenn dies der Fall ist, handelt es sich tatsächlich um eine Funktion, die ihr Argument als ein Array von Zeigern behandelt. Sie sollten daher Ihre Datenstruktur entsprechend zuordnen. Zum Beispiel:

double x1[8] = { 1, 2, ... }; 
double x2[8] = { 3, 4, ... }; 
... 
double* x[6] = { x1, x2, ... }; 

func(x); 
+0

Schön und umfassend. Aber was ist, wenn du das Fn nicht ändern kannst? Wickeln Sie es einfach so ein, dass das Array der obersten Ebene stack-local ist (entweder Stack-Alloc oder ausnahmesicherer Heap). Das heißt, das 2d-Array selbst enthält zusammenhängende 1d-Arrays, auf die Sie einfach zeigen können. –

+0

Alternativ können Sie die Syntax des netten Initialisierers für eine Reihe separater 1D-Arrays verwenden und auf diese verweisen. Array-Initialisierersyntax ist nur im Bereich der obersten Ebene verfügbar, oder? –

+0

Guter Punkt, ich werde bearbeiten. Array-Initialisierer ist in jedem Bereich verfügbar (einschließlich local/auto), aber nicht in "new". –

-1
func(double *arr[100]) 

Sie müssen den Compiler die Größe der Dimension erzählen, damit er die Adresse korrekt erstellen können

arr[y][x] 

in

arr[100*x+y] 

dreht Wenn Sie definieren Ihre Funktion als func (double ** a), dann sagen Sie einen Zeiger auf ein Array von Zeigern als Dmckee wies