Je veux imprimer le contenu d'un vecteur en C ++, voici ce que j'ai:
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <vector>
#include <sstream>
#include <cstdio>
using namespace std;
int main()
{
ifstream file("maze.txt");
if (file) {
vector<char> vec(istreambuf_iterator<char>(file), (istreambuf_iterator<char>()));
vector<char> path;
int x = 17;
char entrance = vec.at(16);
char firstsquare = vec.at(x);
if (entrance == 'S') {
path.push_back(entrance);
}
for (x = 17; isalpha(firstsquare); x++) {
path.push_back(firstsquare);
}
for (int i = 0; i < path.size(); i++) {
cout << path[i] << " ";
}
cout << endl;
return 0;
}
}
Comment imprimer le contenu du vecteur à l'écran?
Réponses:
Pour répondre à votre question, vous pouvez utiliser un itérateur:
Si vous souhaitez modifier le contenu du vecteur dans la boucle for, utilisez
iterator
plutôt queconst_iterator
.Mais il y a beaucoup plus à dire à ce sujet. Si vous voulez juste une réponse que vous pouvez utiliser, vous pouvez vous arrêter ici; sinon, lisez la suite.
auto (C ++ 11) / typedef
Ce n'est pas une autre solution, mais un complément à la
iterator
solution ci-dessus . Si vous utilisez la norme C ++ 11 (ou ultérieure), vous pouvez utiliser leauto
mot clé pour améliorer la lisibilité:Mais le type de
i
sera non-const (ie, le compilateur utiliserastd::vector<char>::iterator
comme type dei
).Dans ce cas, vous pourriez tout aussi bien utiliser un
typedef
(non limité à C ++ 11, et très utile à utiliser quand même):compteur
Vous pouvez bien sûr utiliser un type entier pour enregistrer votre position dans la
for
boucle:Si vous comptez le faire, il est préférable d'utiliser les types de membres du conteneur, s'ils sont disponibles et appropriés.
std::vector
a un type de membre appelésize_type
pour ce travail: c'est le type renvoyé par lasize
méthode.Pourquoi ne pas simplement l'utiliser sur la
iterator
solution? Pour les cas simples, vous pourriez aussi bien, mais le fait est que laiterator
classe est un objet conçu pour faire ce travail pour des objets plus compliqués où cette solution ne sera pas idéale.basé sur une plage pour la boucle (C ++ 11)
Voir la solution de Jefffrey . En C ++ 11 (et versions ultérieures), vous pouvez utiliser la nouvelle
for
boucle basée sur une plage , qui ressemble à ceci:Puisque
path
est un vecteur d'éléments (explicitementstd::vector<char>
), l'objeti
est de type de l'élément du vecteur (c'est-à-dire, explicitement, il est de typechar
). L'objeti
a une valeur qui est une copie de l'élément réel dans l'path
objet. Ainsi, toutes les modifications apportées ài
la boucle ne sont pas conservées enpath
soi. De plus, si vous voulez faire respecter le fait que vous ne voulez pas être en mesure de changer la valeur copiée dei
la boucle, vous pouvez forcer le type dei
êtreconst char
comme ceci:Si vous souhaitez modifier les éléments dans
path
, vous pouvez utiliser une référence:et même si vous ne souhaitez pas modifier
path
, si la copie d'objets est coûteuse, vous devez utiliser une référence const au lieu de copier par valeur:std :: copy
Voir la réponse de Joshua . Vous pouvez utiliser l'algorithme STL
std::copy
pour copier le contenu vectoriel sur le flux de sortie. C'est une solution élégante si vous êtes à l'aise avec elle (et d'ailleurs, elle est très utile, pas seulement dans ce cas d'impression du contenu d'un vecteur).std :: for_each
Voir la solution de Max . L'utilisation
std::for_each
est exagérée pour ce scénario simple, mais c'est une solution très utile si vous vouliez faire plus que simplement imprimer à l'écran: l'utilisationstd::for_each
vous permet d'effectuer n'importe quelle opération (raisonnable) sur le contenu du vecteur.surcharge ostream :: operator <<
Voir la réponse de Chris , c'est plus un complément aux autres réponses puisque vous devrez toujours implémenter l'une des solutions ci-dessus dans la surcharge. Dans son exemple, il a utilisé un compteur en
for
boucle. Par exemple, voici comment utiliser rapidement la solution de Joshua :L'utilisation de l'une des autres solutions doit être simple.
conclusion
Toutes les solutions présentées ici fonctionneront. C'est à vous et au code sur lequel on est le "meilleur". Tout ce qui est plus détaillé est probablement préférable de laisser une autre question où les avantages / inconvénients peuvent être correctement évalués; mais comme toujours, la préférence de l'utilisateur jouera toujours un rôle: aucune des solutions présentées n'est fausse, mais certaines seront plus jolies pour chaque codeur individuel.
Addenda
Il s'agit d'une solution étendue d'une précédente que j'ai publiée. Étant donné que ce message continuait à attirer l'attention, j'ai décidé de l'étendre et de faire référence aux autres excellentes solutions publiées ici. Mon message original avait une remarque qui dit que si vous aviez l' intention sur la modification de votre vecteur dans une
for
boucle , puis il y a deux méthodes fournies parstd::vector
des éléments d'accès:std::vector::operator[]
qui ne fait pas vérification de limites, etstd::vector::at
qui n'effectue la vérification des limites. En d'autres termes,at
lancera si vous essayez d'accéder à un élément en dehors du vecteur etoperator[]
ne le ferait pas. Je n'ai ajouté ce commentaire, à l'origine, que pour mentionner quelque chose qu'il pourrait être utile de savoir si quelqu'un ne l'a pas déjà fait. Et je ne vois aucune différence maintenant. D'où cet addendum.la source
0
partvector::size()
et que le vecteur n'est pas modifié dans la boucle, il n'est pas nécessaire d'utiliserat()
et d'encourir les frais supplémentaires de vérification des limites. Cela dit, j'irais avec un itérateur comme vous le suggérez.at
si rien dans la boucle ne modifie le vecteur, mais j'ai pensé le mentionner juste au cas où le vecteur serait modifié dans la boucle (non recommandé que cela puisse être) et parce qu'il n'obtient jamais de mentionner et il pourrait être utile, au moins, de le savoir.for (auto const &i: path) std::cout << i << ' ';
Un moyen beaucoup plus simple de le faire est d'utiliser l' algorithme de copie standard :
L'ostream_iterator est ce qu'on appelle un adaptateur d'itérateur . Il est modélisé sur le type à imprimer dans le flux (dans ce cas,
char
).cout
(aka sortie console) est le flux sur" "
lequel nous voulons écrire, et le caractère espace ( ) est ce que nous voulons imprimer entre chaque élément stocké dans le vecteur.Cet algorithme standard est puissant, tout comme de nombreux autres. La puissance et la flexibilité que la bibliothèque standard vous offre sont ce qui la rend si géniale. Imaginez: vous pouvez imprimer un vecteur sur la console avec une seule ligne de code. Vous n'avez pas à vous occuper de cas particuliers avec le caractère séparateur. Vous n'avez pas à vous soucier des boucles for. La bibliothèque standard fait tout pour vous.
la source
vector<pair<int, struct node>>
. Comment utiliser la méthode ci-dessus pour imprimer ce vecteur?operator<<
fonction pour votre paire spécifique <>.En C ++ 11, vous pouvez désormais utiliser une boucle for basée sur une plage :
la source
char
s, il est probable que le passage par référence constante soit en réalité plus coûteux que par valeur. Mais nous parlons ici de super micro optimisations.Je pense que la meilleure façon de le faire est de simplement surcharger
operator<<
en ajoutant cette fonction à votre programme:Ensuite, vous pouvez utiliser le
<<
opérateur sur n'importe quel vecteur possible, en supposant que ses éléments ont égalementostream& operator<<
défini:Les sorties:
la source
last
àsize_t
.size_t last = v.size() - 1;
semble redondant, vous pouvez utiliser laif (i) out << ", ";
condition avant leout << v[i];
lienoperator<<
. Exempleif (i != last)
chaque fois dans la boucle? Au lieu de cela, si le conteneur ne soit pas vide , alors (a) envoyer le premier élément, puis (b) envoyer en boucle les autres éléments, l' impression du séparateur première (comme un préfixe). Aucun test de boucle interne (à l'exception de la condition de boucle elle-même) n'est requis. Un seul test hors boucle est requis.Que diriez-vous de
for_each
+ expression lambda :Bien sûr, une gamme basée sur est la solution la plus élégante pour cette tâche concrète, mais celle-ci offre également de nombreuses autres possibilités.
Explication
L'
for_each
algorithme prend une plage d'entrée et un objet appelable , appelant cet objet sur chaque élément de la plage. Une plage d'entrée est définie par deux itérateurs . Un objet appelable peut être une fonction, un pointeur vers une fonction, un objet d'une classe qui surcharge() operator
ou comme dans ce cas, une expression lambda . Le paramètre de cette expression correspond au type des éléments du vecteur.La beauté de cette implémentation est la puissance que vous obtenez des expressions lambda - vous pouvez utiliser cette approche pour beaucoup plus de choses que simplement imprimer le vecteur.
la source
Copiez simplement le conteneur sur la console.
Devrait produire:
la source
Le problème est probablement dans la boucle précédente:
(x = 17; isalpha(firstsquare); x++)
. Cette boucle ne fonctionnera pas du tout (si ellefirstsquare
n'est pas alpha) ou s'exécutera pour toujours (si elle est alpha). La raison en est quefirstsquare
cela ne change pas car ilx
est incrémenté.la source
En C ++ 11, une boucle for basée sur une plage peut être une bonne solution:
Production:
la source
Utilisation
std::copy
mais sans séparateur arrière supplémentaireUne approche alternative / modifiée utilisant
std::copy
(comme à l'origine utilisée dans la réponse @JoshuaKravtiz ) mais sans inclure un séparateur de fin supplémentaire après le dernier élément:Exemple d'utilisation appliquée au conteneur d'un type POD personnalisé:
la source
opérateur de surcharge <<:
Usage:
la source
Je vois deux problèmes. Comme indiqué dans
for (x = 17; isalpha(firstsquare); x++)
il y a soit une boucle infinie ou jamais exécutée du tout, et aussiif (entrance == 'S')
si le caractère d'entrée est différent de `` S '', alors rien n'est poussé vers le vecteur de chemin, le rendant vide et n'imprimant donc rien à l'écran. Vous pouvez tester cette dernière vérificationpath.empty()
ou impressionpath.size()
.Quoi qu'il en soit, ne serait-il pas préférable d'utiliser une chaîne au lieu d'un vecteur? Vous pouvez également accéder au contenu de la chaîne comme un tableau, rechercher des caractères, extraire des sous-chaînes et imprimer la chaîne facilement (sans boucle).
Tout faire avec des chaînes pourrait être le moyen de l'écrire de manière moins compliquée et de repérer plus facilement le problème.
la source
Cette réponse est basée sur la réponse de Zorawar, mais je n'ai pas pu laisser de commentaire là-bas.
Vous pouvez rendre la version auto (C ++ 11) / typedef const en utilisant cbegin et cend à la place
la source
En C ++ 11 ''
la source
la source
Cela a fonctionné pour moi:
la source
Pour ceux qui sont intéressés: j'ai écrit une solution généralisée qui prend le meilleur des deux mondes, est plus généralisée à tout type de plage et met des guillemets autour des types non arithmétiques (souhaités pour les types de type chaîne). De plus, cette approche ne devrait pas avoir de problèmes ADL et éviter également les «surprises» (car elle est ajoutée explicitement au cas par cas):
Maintenant, il est assez facile à utiliser sur n'importe quelle gamme:
Le contrôle en forme de chaîne laisse place à amélioration. Je dois également
static_assert
vérifier ma solution pour éviterstd::basic_string<>
, mais je l'ai laissée ici pour plus de simplicité.la source
Vous pouvez écrire votre propre fonction:
la source
Pour les personnes qui souhaitent une ligne sans boucles:
Je ne peux pas croire que personne n'ait pensé à cela, mais c'est peut-être à cause de l'approche plus semblable à C. Quoi qu'il en soit, il est parfaitement sûr de le faire sans boucle, dans une ligne, en supposant que le terminal
std::vector<char>
est nul:Mais je voudrais envelopper cela dans l'
ostream
opérateur, comme l'a suggéré @Zorawar, juste pour être sûr:Nous pouvons obtenir un comportement similaire en utilisant à la
printf
place:REMARQUE:
L'
ostream
opérateur surchargé doit accepter le vecteur comme non-const. Cela pourrait rendre le programme non sécurisé ou introduire du code mal utilisé. De plus, comme le caractère nul est ajouté, une réallocation de lastd::vector
peut se produire. Ainsi, l'utilisation de boucles for avec des itérateurs sera probablement plus rapide.la source
fprintf(stdout, "%s\n", &test[0]);
n'est pas différent destd::cout << test.data()
, les deux nécessitent un vecteur à terminaison nulle. 2. L'opérateur "Mais je voudrais envelopper cela dans l'opérateur ostream"<<
qui modifie l'opérande droit est une très mauvaise idée.fprintf(stdout, "%s\n", &test[0]);
depuis longtemps le code sans que cela ne me pose aucun problème. Intéressant! Et je suis d'accord que ce n'est pas si agréable de modifier le vecteur dans l'ostream
opérateur, mais je n'aime pas à la fois le bouclage manuel et l' utilisation d'itérateurs. D'une certaine manière, je pense que pour des opérations simples comme l'impression d'unestd::vector<char>
bibliothèque standard, cela devrait cacher ces choses. Mais C ++ se développe constamment, il pourrait arriver bientôt.