12 Stimmen

Übergabe eines Arrays mit unbekannter Größe an eine Funktion

Angenommen, ich habe eine Funktion namens MyFunction(int myArray[][]), die Array-Manipulationen durchführt.

Wenn ich die Parameterliste so schreibe, wird der Compiler beschweren, dass er die Größe des Arrays zur Kompilierzeit kennen muss. Gibt es eine Möglichkeit, die Parameterliste umzuschreiben, sodass ich ein Array beliebiger Größe an die Funktion übergeben kann?

Die Größe meines Arrays wird durch zwei static const ints in einer Klasse definiert, aber der Compiler akzeptiert etwas wie MyFunction(int myArray[Board::ROWS][Board::COLS]) nicht.

Was ist, wenn ich das Array in einen Vektor konvertieren könnte und dann den Vektor an MyFunction übergebe? Gibt es eine Einzeilige Konvertierung, die ich verwenden kann, oder muss ich die Konvertierung manuell durchführen?

14voto

AnT Punkte 300728

In der Programmiersprache C++ müssen multidimensionale Array-Deklarationen immer alle Größen außer möglicherweise der ersten Größe enthalten. Daher ist das, was du versuchst zu tun, nicht möglich. Du kannst keinen Parameter vom integrierten Typ eines multidimensionalen Arrays deklarieren, ohne die Größen explizit anzugeben.

Wenn du ein multidimensionales Array mit variabler Größe zur Laufzeit an eine Funktion übergeben möchtest, kannst du den integrierten multidimensionalen Array-Typ vergessen. Eine mögliche Lösung hier ist die Verwendung eines "simulierten" multidimensionalen Arrays (1D-Array von Zeigern auf andere 1D-Arrays; oder ein einfaches 1D-Array, das ein multidimensionales Array durch Indexneuberechnung simuliert).

12voto

M2tM Punkte 4254

In C++ verwenden Sie std::vector, um Arrays zu modellieren, es sei denn, Sie haben einen spezifischen Grund für die Verwendung eines Arrays.

Beispiel für eine mit Nullen gefüllte 3x2-Vektormatrix namens "myArray", die initialisiert wird:

vector< vector > myArray(3, vector(2,0));

Das Weiterreichen dieses Konstrukts ist trivial, und Sie müssen nicht mit der Weitergabe der Länge herumspielen (weil sie verfolgt wird):

void myFunction(vector< vector > &myArray) {
    for (size_t x = 0;x < myArray.size();++x){
        for (size_t y = 0;y < myArray[x].size();++y){
            cout << myArray[x][y] << " ";
        }
        cout << endl;
    }
}

Alternativ können Sie über Iteratoren iterieren:

void myFunction(vector< vector > &myArray) {
    for (vector< vector >::iterator x = myArray.begin();x != myArray.end();++x){
        for (vector::iterator y = x->begin();y != x->end();++y){
            cout << *y << " ";
        }
        cout << endl;
    }
}

In C++0x können Sie das auto-Schlüsselwort verwenden, um die Lösung mit dem Vektoriterator zu bereinigen:

void myFunction(vector< vector > &myArray) {
    for (auto x = myArray.begin();x != myArray.end();++x){
        for (auto y = x->begin();y != x->end();++y){
            cout << *y << " ";
        }
        cout << endl;
    }
}

Und in c++0x wird for_each mit Lambdas möglich

void myFunction(vector< vector > &myArray) {
    for_each(myArray.begin(), myArray.end(), [](const vector &x){
        for_each(x->begin(), x->end(), [](int value){
            cout << value << " ";
        });
        cout << endl;
    });
}

Oder eine range-basierte for-Schleife in c++0x:

void myFunction(vector< vector > &myArray) {
    for (auto x : myArray){
        for (auto y : *x){
            cout << *y << " ";
        }
        cout << endl;
    }
}

*Ich bin gerade nicht in der Nähe eines Compilers und habe diese nicht getestet, bitte zögern Sie nicht, meine Beispiele zu korrigieren.


Wenn Sie die Größe des Arrays zur Kompilierzeit kennen, können Sie Folgendes tun (vorausgesetzt, die Größe ist [x][10]):

MyFunction(int myArray[][10])

Wenn Sie ein Array variabler Länge übergeben müssen (dynamisch allokiert oder möglicherweise nur eine Funktion, die verschiedene Größen von Arrays benötigt), müssen Sie sich mit Zeigern befassen.

Und wie die Kommentare zu dieser Antwort besagen:

boost::multiarray könnten angemessen sein, da es ein mehrdimensionales Array effizienter modelliert. Ein Vektor von Vektoren kann Leistungsprobleme im kritischen Pfadcode haben, aber in typischen Fällen werden Sie wahrscheinlich kein Problem bemerken.

5voto

EboMike Punkte 74805

Geben Sie es als Zeiger weiter und nehmen Sie die Dimension(en) als Argument.

void foo(int *array, int width, int height) {
    // initialisiere xPos und yPos
    assert(xPos >= 0 && xPos < width);
    assert(yPos >= 0 && yPos < height);
    int value = array[yPos * width + xPos];
}

Dies setzt voraus, dass Sie ein einfaches zweidimensionales Array haben, wie int x[50][50].

3voto

Es gibt bereits eine Reihe von Antworten mit den meisten üblichen Vorschlägen: Verwendung von std::vector, Implementierung einer Matrix-Klasse, Bereitstellung der Größe des Arrays im Funktionsargument... Ich werde nur noch eine weitere Lösung auf Basis von nativen Arrays hinzufügen - beachten Sie, dass Sie bei Bedarf eine höhere Abstraktionsebene verwenden sollten.

Wie auch immer:

template 
void function( int (&array)[rows][cols] )
{
   // ...
}

Diese Lösung verwendet eine Referenz zum Array (beachten Sie das & und die Klammer um array) anstelle der Verwendung der Wertübergabe-Syntax. Dadurch zwingt der Compiler das Array nicht, sich in einen Zeiger zu "zerfallen". Dann können die beiden Größen (die als Kompilierzeitkonstanten bereitgestellt werden können) als Template-Argumente definiert werden und der Compiler wird die Größen für Sie ableiten.

HINWEIS: Sie erwähnen in der Frage, dass die Größen tatsächlich statische Konstanten sind, die Sie im Funktionskopf verwenden sollten, wenn Sie den Wert in der Klassendeklaration bereitstellen:

struct test {
   static const int rows = 25;
   static const int cols = 80;
};
void function( int *array[80], int rows ) {
   // ...
}

Beachten Sie, dass ich in der Signatur die doppelte Dimension des Arrays gegen einen Zeiger auf ein Array geändert habe. Der Grund dafür ist, dass das ist, wie der Compiler es sowieso interpretiert, und auf diese Weise ist klar, dass es keine Garantie dafür gibt, dass der Aufrufer der Funktion ein Array genau mit 25 Zeilen übergibt (der Compiler wird es nicht erzwingen), und somit ist der Bedarf an dem zweiten Integer-Argument ersichtlich, in dem der Aufrufer die Anzahl der Zeilen übergibt.

2voto

André Caron Punkte 43205

Der Compiler beschwert sich, weil er die Größe aller außer der ersten Dimension kennen muss, um ein Element im Array ansprechen zu können. Zum Beispiel im folgenden Code:

int array[M][N];
// ...
array[i][j] = 0;

Um auf das Element zuzugreifen, generiert der Compiler etwas Ähnliches wie folgt:

*(array+(i*N+j)) = 0;

Daher müssen Sie Ihre Signatur wie folgt neu schreiben:

MyFunction(int array[][N])

in diesem Fall bleiben Sie bei einer festen Dimension stecken oder Sie entscheiden sich für eine allgemeinere Lösung wie eine (benutzerdefinierte) dynamische 2D-Array-Klasse oder einen vector >.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X