109 votes

Quelle est la meilleure façon de faire une boucle arrière en C / C # / C ++?

J'ai besoin de revenir en arrière dans un tableau, j'ai donc un code comme celui-ci:

 for (int i = myArray.Length - 1; i >= 0; i--)
{
    // Do something
    myArray[i] = 42;
}
 

Existe-t-il une meilleure façon de le faire?

Mise à jour: J'espérais que C # avait peut-être un mécanisme intégré pour cela, comme:

 foreachbackwards (int i in myArray)
{
    // so easy
}
 

Mise à jour 2: Il existe de meilleurs moyens. Rune prend le prix avec:

 for (int i = myArray.Length; i-- > 0; )
{    
    //do something
}
//or
for (int i = myArray.Length; i --> 0; )
{
    // do something
}
 

qui a l'air encore mieux en C normal (grâce à Twotymz):

 for (int i = lengthOfArray; i--; )
{    
    //do something
}
 

120voto

En C++, vous basicially avez le choix entre une itération à l'aide des itérateurs, ou des indices. Selon que vous avez un simple tableau, ou un std::vector, vous utilisez des techniques différentes.

En utilisant std::vector

À l'aide des itérateurs

C++ permet de le faire à l'aide de std::reverse_iterator:

for(std::vector<T>::reverse_iterator it = v.rbegin(); it != v.rend(); ++it) {
    /* std::cout << *it; ... */
}

À l'aide d'indices

La unsigned partie intégrante de type retourné par std::vector::la taille n'est pas toujours std::size_t . Il peut être plus ou moins. Ceci est crucial pour la boucle de travailler.

for(std::vector<int>::size_type i = someVector.size() - 1; 
    i != (std::vector<int>::size_type) -1; i--) {
    /* std::cout << someVector[i]; ... */
}

Il travaille, depuis unsigned intégrale types de valeurs sont définies par le biais de modulo leur nombre de bits. Ainsi, si vous définissez -N, vous vous retrouvez à l' (2 ^ BIT_SIZE) -N

À L'Aide De Tableaux

À l'aide des itérateurs

Nous sommes en utilisant std::reverse_iterator à faire de l'itération.

for(std::reverse_iterator<element_type*> it(a + sizeof a / sizeof *a), itb(a); 
    it != itb; 
    ++it) {
    /* std::cout << *it; .... */
}

À l'aide d'indices

Nous pouvons utiliser std::size_t ici, contrairement à ci-dessus, depuis sizeof renvoie toujours std::size_t par définition.

for(std::size_t i = (sizeof a / sizeof *a) - 1; i != (std::size_t) -1; i--) {
   /* std::cout << a[i]; ... */
}

En évitant les pièges avec sizeof appliquée à des pointeurs

En fait le mode de détermination de la taille d'un tableau suce. Si l'un est en fait un pointeur au lieu d'un tableau (ce qui arrive assez souvent, et les débutants vont confondre), il en silence à l'échec. Une meilleure solution est d'utiliser les éléments suivants, qui va échouer au moment de la compilation, si un pointeur:

template<typename T, std::size_t N> char (& array_size(T(&)[N]) )[N];

Il fonctionne par l'obtention de la taille du tableau transmis en premier, puis déclarant à renvoyer une référence à un tableau de type char de la même taille. char est défini pour avoir sizeof 1. Ainsi, le tableau retourné doit avoir un sizeof de N * 1, qui est ce que nous sommes à la recherche pour, avec seulement le moment de la compilation, de l'évaluation et de zéro gestion d'exécution.

Au lieu de faire

(sizeof a / sizeof *a)

Modifier votre code, de sorte que c'est maintenant

(sizeof array_size(a))

56voto

Jay Bazuzi Points 20462

En C # , à l'aide de Visual Studio 2005 ou version ultérieure, tapez 'forr' et appuyez sur [TAB] [TAB] . Cela va s'étendre à une boucle for qui recule dans une collection.

Il est si facile de se tromper (du moins pour moi), que je pensais que l'insertion de cet extrait serait une bonne idée.

Cela dit, j'aime Array.Reverse() / Enumerable.Reverse() et ensuite, il est plus facile de remonter en avant - ils indiquent plus clairement l'intention.

18voto

Keltex Points 17151

En C # avec Linq :

 foreach(var item in myArray.Reverse())
{
    // do something
}
 

11voto

Adam Rosenfield Points 176408

C'est certainement le meilleur moyen pour tout tableau dont la longueur est un type intégral signé. Pour les tableaux dont la longueur est un type entier non signé (par exemple, un std::vector en C ++), vous devez alors modifier légèrement la condition de fin:

 for(size_t i = myArray.size() - 1; i != (size_t)-1; i--)
    // blah
 

Si vous venez de dire i >= 0 , cela est toujours vrai pour un entier non signé, la boucle sera donc une boucle infinie.

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