Comment retourner un tableau d’une fonction?

Comment puis-je retourner un tableau à partir d’une méthode et comment dois-je le déclarer?

int[] test(void); // ?? 

int* test();

mais ce serait “plus de C ++” pour utiliser des vecteurs:

std::vector< int > test();

MODIFIER
Je vais clarifier un point. Puisque vous avez mentionné C ++, j’irai avec les new[] opérateurs new[] et delete[] , mais c’est la même chose avec malloc / free.

Dans le premier cas, vous écrirez quelque chose comme:

 int* test() { return new int[size_needed]; } 

mais ce n’est pas une bonne idée car le client de votre fonction ne connaît pas vraiment la taille du tableau que vous retournez, bien que le client puisse le libérer en toute sécurité avec un appel à delete[] .

 int* theArray = test(); for (size_t i; i < ???; ++i) { // I don't know what is the array size! // ... } delete[] theArray; // ok. 

Une meilleure signature serait celle-ci:

 int* test(size_t& arraySize) { array_size = 10; return new int[array_size]; } 

Et votre code client serait maintenant:

 size_t theSize = 0; int* theArray = test(theSize); for (size_t i; i < theSize; ++i) { // now I can safely iterate the array // ... } delete[] theArray; // still ok. 

Comme il s'agit de C ++, `std :: vector est une solution largement utilisée:

 std::vector test() { std::vector vector(10); return vector; } 

Maintenant, vous n'avez plus besoin d'appeler delete[] , car il sera géré par l'object, et vous pouvez le parcourir en toute sécurité avec:

 std::vector v = test(); std::vector::iterator it = v.begin(); for (; it != v.end(); ++it) { // do your things } 

ce qui est plus facile et plus sûr.

Comment puis-je retourner un tableau dans une méthode c ++ et comment dois-je le déclarer? int [] test (void); ??

Cela ressemble à une question simple, mais en C ++, vous avez plusieurs options. Tout d’abord, vous devriez préférer …

  • std::vector<> , qui se développe de manière dynamic en fonction du nombre d’éléments que vous rencontrez à l’exécution, ou

  • std::array<> (introduit avec C ++ 11), qui stocke toujours un certain nombre d’éléments spécifiés au moment de la compilation,

… comme ils gèrent la mémoire pour vous, assurant un comportement correct et simplifiant considérablement les choses:

 std::vector fn() { std::vector x; x.push_back(10); return x; } std::array fn2() // C++11 { return {3, 4}; } void caller() { std::vector a = fn(); const std::vector& b = fn(); // extend lifetime but read-only // b valid until scope exit/return std::array c = fn2(); const std::array& d = fn2(); } 

La pratique de créer une référence const aux données renvoyées peut parfois éviter une copie, mais vous pouvez normalement vous fier uniquement à l’optimisation de la valeur de retour ou, pour la sémantique de déplacement vector mais pas de déplacement (introduite avec C ++ 11).

Si vous voulez vraiment utiliser un tableau intégré (distinct de la classe de bibliothèque Standard appelée array mentionné ci-dessus), l’appelant peut réserver de l’espace et indiquer à la fonction de l’utiliser:

 void fn(int x[], int n) { for (int i = 0; i < n; ++i) x[i] = n; } void caller() { // local space on the stack - destroyed when caller() returns int x[10]; fn(x, sizeof x / sizeof x[0]); // or, use the heap, lives until delete[](p) called... int* p = new int[10]; fn(p, 10); } 

Une autre option consiste à envelopper le tableau dans une structure qui, contrairement aux tableaux bruts, est légale à renvoyer par valeur à partir d’une fonction:

 struct X { int x[10]; }; X fn() { X x; xx[0] = 10; // ... return x; } void caller() { X x = fn(); } 

En commençant par ce qui précède, si vous êtes bloqué en utilisant C ++ 03, vous voudrez peut-être le généraliser en quelque chose de plus proche du std::array C ++ 11 std::array

 template  struct array { T& operator[](size_t n) { return x[n]; } const T& operator[](size_t n) const { return x[n]; } size_t size() const { return N; } // iterators, constructors etc.... private: T x[N]; }; 

Une autre option consiste à faire en sorte que la fonction appelée alloue de la mémoire sur le tas:

 int* fn() { int* p = new int[2]; p[0] = 0; p[1] = 1; return p; } void caller() { int* p = fn(); // use p... delete[] p; } 

Pour simplifier la gestion des objects de segment de mémoire, de nombreux programmeurs C ++ utilisent des "pointeurs intelligents" qui assurent la suppression lorsque les pointeurs vers l'object quittent leurs étendues. Avec C ++ 11:

 std::shared_ptr p(new int[2], [](int* p) { delete[] p; } ); std::unique_ptr p(new int[3]); 

Si vous êtes bloqué sur C ++ 03, la meilleure option est de voir si la bibliothèque de boost est disponible sur votre machine: elle fournit boost::shared_array .

Une autre option est d'avoir de la mémoire statique réservée par fn() , bien que ce soit NOT THREAD SAFE, et signifie que chaque appel à fn() écrase les données vues par quiconque garde des pointeurs des appels précédents. Cela dit, cela peut être pratique (et rapide) pour un code simple thread unique.

 int* fn(int n) { static int x[2]; // clobbered by each call to fn() x[0] = n; x[1] = n + 1; return x; // every call to fn() returns a pointer to the same static x memory } void caller() { int* p = fn(3); // use p, hoping no other thread calls fn() meanwhile and clobbers the values... // no clean up necessary... } 

Il n’est pas possible de retourner un tableau à partir d’une fonction C ++. 8.3.5 [dcl.fct] / 6:

Les fonctions ne doivent pas avoir de type de retour de type tableau ou fonction […]

Les alternatives les plus couramment choisies consistent à renvoyer une valeur de type de classe où cette classe contient un tableau, par exemple

 struct ArrayHolder { int array[10]; }; ArrayHolder test(); 

Ou pour renvoyer un pointeur sur le premier élément d’un tableau statiquement ou dynamicment alloué, la documentation doit indiquer à l’utilisateur s’il doit (et si oui, comment il devrait) libérer le tableau vers lequel pointe le pointeur renvoyé.

Par exemple

 int* test2() { return new int[10]; } int* test3() { static int array[10]; return array; } 

Bien qu’il soit possible de renvoyer une référence ou un pointeur sur un tableau, il est extrêmement rare qu’il s’agisse d’une syntaxe plus complexe sans avantage pratique par rapport aux méthodes ci-dessus.

 int (&test4())[10] { static int array[10]; return array; } int (*test5())[10] { static int array[10]; return &array; } 

Eh bien, si vous voulez renvoyer votre tableau à partir d’une fonction, vous devez vous assurer que les valeurs ne sont pas stockées dans la stack car elles disparaîtront lorsque vous quitterez la fonction.

Donc, soit rendre votre tableau statique ou allouer la mémoire (ou le transmettre mais votre tentative initiale est avec un paramètre void). Pour votre méthode, je définirais comme ceci:

 int *gnabber(){ static int foo[] = {1,2,3} return foo; } 

“Comment puis-je retourner un tableau dans une méthode c ++ et comment dois-je le déclarer? int [] test (void); ??”

 template  class Array { X *m_data; int m_size; public: // there constructor, destructor, some methods int Get(X* &_null_pointer) { if(!_null_pointer) { _null_pointer = new X [m_size]; memcpy(_null_pointer, m_data, m_size * sizeof(X)); return m_size; } return 0; } }; 

juste pour int

 class IntArray { int *m_data; int m_size; public: // there constructor, destructor, some methods int Get(int* &_null_pointer) { if(!_null_pointer) { _null_pointer = new int [m_size]; memcpy(_null_pointer, m_data, m_size * sizeof(int)); return m_size; } return 0; } }; 

Exemple

 Array array; float *n_data = NULL; int data_size; if(data_size = array.Get(n_data)) { // work with array } delete [] n_data; 

exemple pour int

 IntArray array; int *n_data = NULL; int data_size; if(data_size = array.Get(n_data)) { // work with array } delete [] n_data;