Rückgabe eines mehrdimensionalen Arrays von der Funktion
Lesezeit: 5 Minuten
justin
Wie gebe ich ein mehrdimensionales Array zurück, das in a gespeichert ist? private Bereich meiner Klasse?
class Myclass {
private:
int myarray[5][5];
public:
int **get_array();
};
// This does not work:
int **Myclass::get_array() {
return myarray;
}
Ich bekomme folgenden Fehler:
kann nicht konvertieren int (*)[5][5] zu int** im Gegenzug
was ist gitter sollte es nicht sein myarray?
– Holzstok
15. September 10 um 10:08 Uhr
Das Zurückgeben eines direkten Verweises auf ein privates Element ist möglicherweise nicht immer eine gute Idee – Sie brechen damit effektiv die Kapselung und ermöglichen jedem, auf Ihr privates Element zuzugreifen und es zu ändern. Dies kann in Ihrem Design akzeptabel sein oder nicht.
– Peter Török
15. September 10 um 10:11 Uhr
@MIkhail: Da Justin seit dem Posten dieser Frage nicht mehr online war, habe ich mir die Freiheit genommen, es zu beheben.
– sbi
13. November 10 um 12:34 Uhr
Sie können die Matrix-Bibliothek verwenden.
– Amir Fo
16. Juni 18 um 9:34 Uhr
Besucher
Ein zweidimensionales Array zerfällt nicht von Zeiger zu Zeiger auf Ints. Es zerfällt zu einem Zeiger auf Arrays von Ints – das heißt, nur die erste Dimension zerfällt zu einem Zeiger. Der Zeiger zeigt nicht auf int-Zeiger, die, wenn sie inkrementiert werden, um die Größe eines Zeigers vorrücken, sondern auf Arrays von 5 ganzen Zahlen.
class Myclass {
private:
int myarray[5][5];
public:
typedef int (*pointer_to_arrays)[5]; //typedefs can make things more readable with such awkward types
pointer_to_arrays get_array() {return myarray;}
};
int main()
{
Myclass o;
int (*a)[5] = o.get_array();
//or
Myclass::pointer_to_arrays b = o.get_array();
}
Ein Zeiger auf Zeiger (int**) wird verwendet, wenn jedes Subarray separat zugewiesen wird (das heißt, Sie haben ursprünglich ein Array von Zeigern).
int* p[5];
for (int i = 0; i != 5; ++i) {
p[i] = new int[5];
}
Hier haben wir ein Array von fünf Zeigern, die jeweils auf das erste Element in einem separaten Speicherblock zeigen, insgesamt 6 verschiedene Speicherblöcke.
In einem zweidimensionalen Array erhalten Sie einen einzelnen zusammenhängenden Speicherblock:
int arr[5][5]; //a single block of 5 * 5 * sizeof(int) bytes
Sie sollten sehen, dass das Speicherlayout dieser Dinge völlig unterschiedlich ist und diese Dinge daher nicht auf die gleiche Weise zurückgegeben und weitergegeben werden können.
Es gibt zwei mögliche Typen, die Sie zurückgeben können, um Zugriff auf Ihr internes Array zu gewähren. Der alte C-Stil würde zurückkehren int *[5]da das Array leicht in einen Zeiger auf das erste Element zerfällt, das vom Typ ist int[5].
int (*foo())[5] {
static int array[5][5] = {};
return array;
}
Jetzt können Sie auch eine richtige Referenz auf das interne Array zurückgeben, die einfachste Syntax wäre über eine Typedef:
typedef int (&array5x5)[5][5];
array5x5 foo() {
static int array[5][5] = {};
return array;
}
Oder etwas umständlicher ohne typedef:
int (&foo())[5][5] {
static int array[5][5] = {};
return array;
}
Der Vorteil der C++-Version besteht darin, dass der tatsächliche Typ beibehalten wird, was bedeutet, dass die tatsächliche Größe des Arrays auf der Seite des Aufrufers bekannt ist.
Seien Sie jedoch vorsichtig, wie Sie diese Typedefs verwenden, manchmal: delete[] new array5x5() (sieht aus wie neu, ist aber wirklich neu[]).
– Roger Pate
13. November 10 um 10:45 Uhr
Um einen Zeiger auf Ihr Array von Array-Mitgliedern zurückzugeben, ist der Typ erforderlich int (*)[5]nicht int **:
class Myclass {
private:
int myarray[5][5];
public:
int (*get_array())[5];
};
int (*Myclass::get_array())[5] {
return myarray;
}
Wie gebe ich ein mehrdimensionales Array zurück, das in einem privaten Feld versteckt ist?
Wenn es versteckt werden soll, warum gibst du es überhaupt zurück?
Wie auch immer, Sie können keine Arrays von Funktionen zurückgeben, aber Sie können einen Zeiger auf das erste Element zurückgeben. Was ist das erste Element eines 5×5-Arrays von Ints? Natürlich ein Array von 5 Ints:
int (*get_grid())[5]
{
return grid;
}
Alternativ könnten Sie das gesamte Array als Referenz zurückgeben:
int (&get_grid())[5][5]
{
return grid;
}
…Willkommen in der Hölle der C-Deklarator-Syntax 😉
Darf Ich vorschlagen std::vector<std::vector<int> > oder boost::multi_array<int, 2> stattdessen?
Jarod42
Einfacher wäre decltype(auto) (seit C++14)
decltype(auto) get_array() { return (myarray); } // Extra parents to return reference
dann decltype (seit C++11) (Member sollte aber vor der Methode deklariert werden)
auto get_array() -> decltype((this->myarray)) { return myarray; }
// or
auto get_array() -> decltype(this->myarray)& { return myarray; }
dann typedef weg:
using int2D = int[5][5]; // since C++11
// or
typedef int int2D[5][5];
int2D& get_array() { return myarray; }
da die reguläre Syntax sehr hässlich ist:
int (&get_array())[5][5] { return myarray; }
Verwenden std::array<std::array<int, 5>, 5> (seit C++11) hätte eine natürlichere Syntax.
Ich habe es geschafft, diese Funktion in C++0x mithilfe der automatischen Typableitung zum Laufen zu bringen. Ohne das schaffe ich es aber nicht. Native C-Arrays werden in C++ nicht sehr gut unterstützt – ihre Syntax ist äußerst abscheulich. Sie sollten eine Wrapper-Klasse verwenden.
template<typename T, int firstdim, int seconddim> class TwoDimensionalArray {
T data[firstdim][seconddim];
public:
T*& operator[](int index) {
return data[index];
}
const T*& operator[](int index) const {
return data[index];
}
};
class Myclass {
public:
typedef TwoDimensionalArray<int, 5, 5> arraytype;
private:
arraytype myarray;
public:
arraytype& get_array() {
return myarray;
}
};
int main(int argc, char **argv) {
Myclass m;
Myclass::arraytype& var = m.get_array();
int& someint = var[0][0];
}
Dieser Code lässt sich gut kompilieren. Sie können eine vorgefertigte Wrapper-Klasse innerhalb von Boost (boost::array) erhalten, die den ganzen Kram unterstützt.
Harald
Ändern Sie Ihre ints in int[][]’s oder versuchen Sie es mit int[,] stattdessen?
… und int[][] sollte auch nicht gelten. In diesem Fall ist es wichtig, den Unterschied zwischen Arrays und Zeigern zu verstehen.
– Besucher
15. September 10 um 10:23 Uhr
@David: Eigentlich new int[5, 5] gültiges C++ ist, es macht einfach nicht das, was man denken könnte – es ist dasselbe wie new int[5] Danke an den Komma-Operator 🙂
was ist gitter sollte es nicht sein
myarray
?– Holzstok
15. September 10 um 10:08 Uhr
Das Zurückgeben eines direkten Verweises auf ein privates Element ist möglicherweise nicht immer eine gute Idee – Sie brechen damit effektiv die Kapselung und ermöglichen jedem, auf Ihr privates Element zuzugreifen und es zu ändern. Dies kann in Ihrem Design akzeptabel sein oder nicht.
– Peter Török
15. September 10 um 10:11 Uhr
@MIkhail: Da Justin seit dem Posten dieser Frage nicht mehr online war, habe ich mir die Freiheit genommen, es zu beheben.
– sbi
13. November 10 um 12:34 Uhr
Sie können die Matrix-Bibliothek verwenden.
– Amir Fo
16. Juni 18 um 9:34 Uhr