Manière correcte de boucle à travers les tableaux c++

Récemment, j'ai trouvé beaucoup d'exemples, la plupart d'entre eux ce qui concerne le C++ 98, de toute façon j'ai créé mon simple-tableau 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:

value of a: Apple
value of a: Banana
value of a: Orange

Segmentation fault

Cela fonctionne bien, sauf le défaut de segmentation à la fin.

Ma question Est, est-ce que ce tableau / boucle est fait un bon moyen? J'utilise C++ 11 donc je voudrais être sûr qu'il correspond aux normes et ne pourrait pas être fait d'une meilleure façon?

28
demandé sur Zeta 2013-11-27 09:51:50

6 réponses

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 d'un objet simple, donne la taille de l' pointeur, pas de l'objet(s) souligné. De toute façon, sizeof ne 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 )

Quant à le faire de la manière c++11, la meilleure façon de le faire c'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 souligné, std::array est préféré en C++11 sur les tableaux bruts; cependant, aucune des autres réponses n'a abordé pourquoi sizeof échoue tel quel, donc je pense toujours que c'est la meilleure réponse.

57
répondu Nicu Stiurca 2015-12-09 04:52:53
string texts[] = {"Apple", "Banana", "Orange"};
for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
{
    cout << "value of a: " << texts[a] << endl;
}

Non. Totalement une mauvaise façon d'itérer à travers un tableau. sizeof(texts) n'est pas égal au nombre d'éléments dans le tableau!

Le moderne, C++11 façons serait de:

  • utiliser std::array si vous voulez un tableau dont la taille est connue à la compilation; ou
  • utiliser std::vector si sa taille dépend de l'exécution

Ensuite, utilisez range-for lors de l'itération.

#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 en direct


Vous pouvez demander, comment est std::array meilleur que le tableau ol' C? Le la réponse est qu'il a la sécurité et les caractéristiques supplémentaires d'autres conteneurs de bibliothèque standard, ressemblant principalement à std::vector. En outre, la réponse est qu'il n'a pas les bizarreries de se décomposer en pointeurs et de perdre ainsi des informations de type, qui, une fois que vous perdez le type de tableau d'origine, vous ne pouvez pas utiliser range-for ou std::begin/end dessus.

14
répondu Mark Garcia 2013-11-27 07:00:55

sizeof vous indique la taille de la chose, et non pas le nombre d'éléments. 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;
}

Démo Ideone: http://ideone.com/6xmSrn

8
répondu kfsone 2013-11-27 05:59:06

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

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

1
répondu bvj 2016-01-10 23:25:34

Si vous avez une très courte liste des éléments que vous souhaitez gérer, vous pouvez utiliser le std::initializer_list introduit dans 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
répondu Phidelux 2018-02-01 09:54:39

Ajoute 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;
}
0
répondu Nuno Rafael Figueiredo 2016-07-22 11:41:40