249 votes

Tableau de retour dans une fonction

J'ai un tableau int arr[5] qui est transmis à une fonction fillarr(int arr[]) :

int fillarr(int arr[])
{
    for(...);
    return arr;
}
  1. Comment puis-je retourner ce tableau ?
  2. Comment vais-je l'utiliser, disons que j'ai renvoyé un pointeur, comment vais-je y accéder ?

58 votes

Dans ce contexte, il n'est pas nécessaire de renvoyer le tableau puisque celui-ci est transmis par référence et que tout changement apporté aux éléments contenus dans "arr" sera perçu en dehors de la fonction.

13 votes

Le retour du tableau est pratique pour enchaîner les fonctions.

6 votes

Tant que vous ne faites pas l'erreur de créer un tableau sur la pile et de renvoyer un pointeur vers ce tableau.

228voto

Brent Nash Points 6337

Dans ce cas, votre variable de tableau arr peut également être traité comme un pointeur sur le début du bloc de votre tableau en mémoire, par une conversion implicite. Cette syntaxe que vous utilisez :

int fillarr(int arr[])

C'est en quelque sorte du sucre syntaxique. Vous pourriez vraiment le remplacer par ceci et cela fonctionnerait toujours :

int fillarr(int* arr)

De la même manière, ce que vous voulez renvoyer de votre fonction est en fait un pointeur sur le premier élément du tableau :

int* fillarr(int arr[])

Et vous pourrez toujours l'utiliser comme vous le feriez avec un tableau normal :

int main()
{
  int y[10];
  int *a = fillarr(y);
  cout << a[0] << endl;
}

47 votes

Pour clarifier, cette "affirmation classique du C++" est fausse ; les tableaux ne sont pas des pointeurs.

31 votes

Rappelez-vous la règle a[i] == *(a + i)

0 votes

Comment dois-je le reformuler ? La variable tableau n'est-elle pas en réalité un pointeur constant sur le début du bloc de mémoire alloué au tableau ? Et puis la variable [] fait de l'arithmétique de pointeur à partir de cette adresse initiale pour localiser les éléments suivants dans le tableau ?

125voto

Potatoswatter Points 70305

Les fonctions C++ ne peuvent pas renvoyer des tableaux de style C par valeur. La solution la plus proche est de renvoyer un pointeur. De plus, un type de tableau dans la liste des arguments est simplement converti en pointeur.

int *fillarr( int arr[] ) { // arr "decays" to type int *
    return arr;
}

Vous pouvez l'améliorer en utilisant un tableau de références pour l'argument et le retour, ce qui empêche la dégradation :

int ( &fillarr( int (&arr)[5] ) )[5] { // no decay; argument must be size 5
    return arr;
}

Avec Boost ou C++11, le passage par référence n'est qu'optionnel et la syntaxe est moins déroutante :

array< int, 5 > &fillarr( array< int, 5 > &arr ) {
    return arr; // "array" being boost::array or std::array
}

En array génère simplement un modèle struct contenant un tableau de style C, ce qui permet d'appliquer une sémantique orientée objet tout en conservant la simplicité initiale du tableau.

4 votes

+1 pour donner un exemple de la façon dont un tableau peut être passé par référence. Mais vous avez tort car vous ne pouvez pas renvoyer un tableau par référence. La syntaxe la plus simple pour y parvenir est d'utiliser un typedef : typedef int array[5]; array& foo(); Mais vous n'avez même pas besoin du typedef si vous voulez écrire ceci : int (&foo())[5] { static int a[5] = {}; return a; } L'exemple de la question est donc le suivant : int (&foo( int (&a)[5] ))[5] { return a; } . C'est simple, n'est-ce pas ?

0 votes

@David : merci, j'ai eu une mauvaise impression en lisant le message de Comeau. error: function returning array is not allowed qui se produit si l'on omet les parens extérieurs dans la syntaxe non typée. Heureusement, aujourd'hui j'ai revu la règle droite-gauche pour une autre question et j'ai réussi à construire la bonne chose après avoir vu que vous disiez que c'était possible avant de voir que vous donniez le code :vP .

2 votes

La réponse de chubsdad contient la citation correcte de la norme : vous ne pouvez pas renvoyer un tableau, mais vous pouvez renvoyer une référence ou un pointeur vers un tableau. Les tableaux ne sont pas copiables (en tant que type) et ne peuvent donc pas être retournés - ce qui impliquerait une copie - et lorsque cette syntaxe est présente, le compilateur convertit l'argument en un pointeur.

29voto

cubuspl42 Points 1293

En C++11, vous pouvez renvoyer std::array .

#include <array>
using namespace std;

array<int, 5> fillarr(int arr[])
{
    array<int, 5> arr2;
    for(int i=0; i<5; ++i) {
        arr2[i]=arr[i]*2;
    }
    return arr2;
}

2 votes

Citation de l'OP : (...) you can consider the array returned arr2, totally another array (...)

25voto

Chubsdad Points 14310

L'article 8.3.5/8 stipule que

"Les fonctions ne doivent pas avoir un type de retour de type tableau ou fonction, bien qu'elles puissent avoir un type de retour de type pointeur ou référence à ces éléments. Il ne doit pas y avoir de tableaux de fonctions, bien qu'il puisse y avoir des tableaux de pointeurs vers des fonctions".

int (&fn1(int (&arr)[5]))[5]{     // declare fn1 as returning refernce to array
   return arr;
}

int *fn2(int arr[]){              // declare fn2 as returning pointer to array
   return arr;
}

int main(){
   int buf[5];
   fn1(buf);
   fn2(buf);
}

7 votes

Votre deuxième fonction renvoie un pointeur sur un int et non un tableau.

0 votes

Encore une fois, pourquoi renvoyer le type lorsque le tableau est mis à jour à l'intérieur de la fonction ? S'agit-il d'une question de bonne pratique ?

10voto

Matt Points 8168

Ceci :

int fillarr(int arr[])

est en fait traité de la même manière que :

int fillarr(int *arr)

Maintenant, si vous voulez vraiment retourner un tableau, vous pouvez changer cette ligne en

int * fillarr(int arr[]){
    // do something to arr
    return arr;
}

Il ne s'agit pas vraiment d'un tableau, mais d'un pointeur sur le début du tableau. l'adresse du tableau.

Mais n'oubliez pas que lorsque vous passez le tableau, vous ne passez qu'un pointeur. Ainsi, lorsque vous modifiez les données du tableau, vous modifiez en fait les données que le pointeur pointe. Par conséquent, avant de passer le tableau, vous devez réaliser que vous avez déjà à l'extérieur le résultat modifié.

par exemple

int fillarr(int arr[]){
   array[0] = 10;
   array[1] = 5;
}

int main(int argc, char* argv[]){
   int arr[] = { 1,2,3,4,5 };

   // arr[0] == 1
   // arr[1] == 2 etc
   int result = fillarr(arr);
   // arr[0] == 10
   // arr[1] == 5    
   return 0;
}

Je suggère que vous envisagiez d'introduire une longueur dans votre fonction fillarr, comme par exemple comme ceci.

int * fillarr(int arr[], int length)

De cette façon, vous pouvez utiliser length pour remplir le tableau à sa longueur, quelle qu'elle soit.

Pour l'utiliser correctement. Faites quelque chose comme ceci :

int * fillarr(int arr[], int length){
   for (int i = 0; i < length; ++i){
      // arr[i] = ? // do what you want to do here
   }
   return arr;
}

// then where you want to use it.
int arr[5];
int *arr2;

arr2 = fillarr(arr, 5);

// at this point, arr & arr2 are basically the same, just slightly
// different types.  You can cast arr to a (char*) and it'll be the same.

Si tout ce que vous voulez faire, c'est donner au tableau des valeurs par défaut, envisagez d'utiliser la fonction memset intégrée.

s memset((int*)&arr, 5, sizeof(int)) ;

Pendant que je parle de ce sujet. Vous dites que vous utilisez C++. Jetez un coup d'œil à l'utilisation des vecteurs stl. Votre code sera probablement plus robuste.

Il existe de nombreux tutoriels. En voici un qui vous donne une idée de la manière de les utiliser. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html

0 votes

Utilice std::copy plus memset C'est plus sûr et plus facile. (Et tout aussi rapide, si ce n'est plus).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X