web-dev-qa-db-fra.com

Chemin correct de la boucle à travers les tableaux C++

Récemment, j'ai trouvé beaucoup d'exemples, la plupart d'entre eux concerne le C++ 98, j'ai quand même créé mon tableau simple et une boucle ( codepad ):

#include <iostream>
using namespace std;

int main ()
{
   string texts[] = {"Apple", "Banana", "Orange"};
   for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
   {
       cout << "value of a: " << texts[a] << endl;
   }

   return 0;
}

Sortie:

valeur de a: pomme 
 valeur de a: banane 
 valeur de a: orange 

 erreur de segmentation

Cela fonctionne bien, sauf la faute de segmentation à la fin.

Ma question est la suivante: ce tableau/boucle est-il bien conçu? J'utilise C++ 11, alors je voudrais être sûr qu'il respecte les normes et ne pourrait pas être amélioré.

38
Lucas

En C/C++ sizeof. donne toujours le nombre d'octets dans l'objet entier et les tableaux sont traités comme un seul objet. Remarque: sizeof un pointeur - vers le premier élément d'un tableau ou vers un seul objet - donne la taille du pointeur , et non de l'objet pointé Quoi qu'il en soit, sizeof donne pas donne le nombre d'éléments dans le tableau (sa longueur). Pour obtenir la longueur, vous devez diviser par la taille de chaque élément. par exemple.,

for( unsigned int a = 0; a < sizeof(texts)/sizeof(texts[0]); a = a + 1 )

Pour le faire à la manière C++ 11, la meilleure façon de le faire est probablement

for(const string &text : texts)
    cout << "value of text: " << text << endl;

Cela permet au compilateur de déterminer le nombre d'itérations dont vous avez besoin.

EDIT: comme d'autres l'ont fait remarquer, std::array est préféré en C++ 11 par rapport aux tableaux bruts; Cependant, aucune des autres réponses n’a expliqué pourquoi sizeof échouait ainsi, alors je pense toujours que c’est la meilleure réponse.

68
Nicu Stiurca
string texts[] = {"Apple", "Banana", "Orange"};
for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
{
    cout << "value of a: " << texts[a] << endl;
}

Nan. Totalement une mauvaise façon de parcourir un tableau. sizeof(texts) n'est pas égal au nombre d'éléments dans le tableau!

Les manières modernes, C++ 11, seraient de:

  • utilisez std::array si vous voulez un tableau dont la taille est connue au moment de la compilation; ou
  • utilisez std::vector si sa taille dépend du temps d'exécution

Ensuite, utilisez range-pour itérer.

#include <iostream>
#include <array>


int main() {
    std::array<std::string, 3> texts = {"Apple", "Banana", "Orange"};
    // ^ An array of 3 elements with the type std::string

    for(const auto& text : texts) {   // Range-for!
        std::cout << text << std::endl;
    }
}

Exemple live


Vous pouvez demander, en quoi std::array est-il meilleur que le vieux tableau 'C? La réponse est qu’il bénéficie de la sécurité et des fonctionnalités supplémentaires d’autres conteneurs de bibliothèques standard, qui ressemblent le plus souvent à std::vector. De plus, la réponse est qu’elle n’a pas l’inconvénient de se désintégrer en pointeurs et donc de perdre les informations de type, lesquelles, une fois que vous perdez le type de tableau original, vous ne pouvez plus utiliser range-for ou std::begin/end.

15
Mark Garcia

sizeof vous indique la taille d'une chose, pas le nombre d'éléments qu'elle contient. Une façon plus C++ 11 de faire ce que vous faites serait:

#include <array>
#include <string>
#include <iostream>

int main()
{
    std::array<std::string, 3> texts { "Apple", "Banana", "Orange" };
    for (auto& text : texts) {
        std::cout << text << '\n';
    }
    return 0;
}

ideone demo: http://ideone.com/6xmSrn

8
kfsone

Ajoutez une valeur d'arrêt au tableau:

#include <iostream>
using namespace std;

int main ()
{
   string texts[] = {"Apple", "Banana", "Orange", ""};
   for( unsigned int a = 0; texts[a].length(); a = a + 1 )
   {
       cout << "value of a: " << texts[a] << endl;
   }

   return 0;
}
1

Si vous souhaitez gérer une très courte liste d'éléments, vous pouvez utiliser le std :: initializer_list introduit en C++ 11 avec auto:

#include <iostream>

int main(int, char*[])
{
    for(const auto& ext : { ".slice", ".socket", ".service", ".target" })
        std::cout << "Handling *" << ext << " systemd files" << std::endl;

    return 0;
}
1
Phidelux

sizeof(texts) sur mon système évalué à 96: nombre d'octets requis pour le tableau et ses instances de chaîne.

Comme mentionné ailleurs, la sizeof(texts)/sizeof(texts[0]) donnerait la valeur de 3 que vous attendiez.

1
bvj