Ich möchte den Inhalt eines Vektors in C ++ ausdrucken. Folgendes habe ich:
#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;
}
}
Wie drucke ich den Inhalt des Vektors auf den Bildschirm?
Antworten:
Um Ihre Frage zu beantworten, können Sie einen Iterator verwenden:
Wenn Sie den Inhalt des Vektors in der for-Schleife ändern möchten, verwenden Sie
iterator
stattconst_iterator
.Aber dazu kann noch viel mehr gesagt werden. Wenn Sie nur eine Antwort wünschen, die Sie verwenden können, können Sie hier aufhören. Ansonsten lesen Sie weiter.
auto (C ++ 11) / typedef
Dies ist keine andere Lösung, sondern eine Ergänzung zu der obigen
iterator
Lösung. Wenn Sie den C ++ 11-Standard (oder höher) verwenden, können Sie dasauto
Schlüsselwort verwenden, um die Lesbarkeit zu verbessern:Der Typ von
i
wird jedoch nicht konstant sein (dh der Compiler wirdstd::vector<char>::iterator
als Typ von verwendeni
).In diesem Fall können Sie auch einfach a verwenden
typedef
(nicht auf C ++ 11 beschränkt und trotzdem sehr nützlich):Zähler
Sie können natürlich einen ganzzahligen Typ verwenden, um Ihre Position in der
for
Schleife aufzuzeichnen :Wenn Sie dies tun, ist es besser, die Elementtypen des Containers zu verwenden, sofern diese verfügbar und angemessen sind. Für diesen Job
std::vector
wird ein Elementtyp aufgerufen:size_type
Dies ist der von dersize
Methode zurückgegebene Typ .Warum nicht einfach über die
iterator
Lösung verwenden? In einfachen Fällen können Sieiterator
dies auch tun , aber der Punkt ist, dass die Klasse ein Objekt ist, das für diese Aufgabe für kompliziertere Objekte entwickelt wurde, bei denen diese Lösung nicht ideal ist.bereichsbasierte for-Schleife (C ++ 11)
Siehe Jefffreys Lösung . In C ++ 11 (und höher) können Sie die neue bereichsbasierte
for
Schleife verwenden, die folgendermaßen aussieht:Da
path
es sich (explizitstd::vector<char>
) um einen Vektor von Elementen handelt , ist das Objekti
vom Typ des Elements des Vektors (dh explizit vom Typchar
). Das Objekti
hat einen Wert, der eine Kopie des tatsächlichen Elements impath
Objekt ist. Somiti
bleiben nicht alle Änderungen in der Schleife an sich erhaltenpath
. Wenn Sie darüber hinaus die Tatsache erzwingen möchten , dass Sie nicht in der Lage sein wollen , den kopierten Wert zu ändern ,i
in der Schleife, können Sie die Art der Gewalti
zu seinconst char
wie folgt aus :Wenn Sie die Elemente in ändern möchten
path
, können Sie eine Referenz verwenden:und selbst wenn Sie nicht ändern möchten, sollten Sie
path
, wenn das Kopieren von Objekten teuer ist, eine const-Referenz verwenden, anstatt nach Wert zu kopieren:std :: copy
Siehe Joshuas Antwort . Sie können den STL-Algorithmus verwenden,
std::copy
um den Vektorinhalt in den Ausgabestream zu kopieren. Dies ist eine elegante Lösung, wenn Sie damit vertraut sind (und außerdem ist sie sehr nützlich, nicht nur in diesem Fall, wenn Sie den Inhalt eines Vektors drucken).std :: for_each
Siehe Max 'Lösung . Die Verwendung
std::for_each
ist für dieses einfache Szenario übertrieben, aber eine sehr nützliche Lösung, wenn Sie mehr als nur auf dem Bildschirm drucken möchten: Mit der Optionstd::for_each
können Sie jede (sinnvolle) Operation am Vektorinhalt ausführen.Überladung ostream :: operator <<
Siehe Chris 'Antwort , dies ist eher eine Ergänzung zu den anderen Antworten, da Sie bei der Überladung noch eine der oben genannten Lösungen implementieren müssen. In seinem Beispiel verwendete er einen Zähler in einer
for
Schleife. So können Sie beispielsweise schnell Joshuas Lösung verwenden :Die Verwendung einer der anderen Lösungen sollte unkompliziert sein.
Fazit
Jede der hier vorgestellten Lösungen funktioniert. Es liegt an Ihnen und dem Code, auf dem man der "Beste" ist. Alles, was detaillierter ist, bleibt wahrscheinlich am besten für eine andere Frage übrig, bei der die Vor- und Nachteile richtig bewertet werden können. Aber wie immer wird die Benutzerpräferenz immer eine Rolle spielen: Keine der vorgestellten Lösungen ist falsch, aber einige sehen für jeden einzelnen Codierer besser aus.
Nachtrag
Dies ist eine erweiterte Lösung einer früheren, die ich veröffentlicht habe. Da dieser Beitrag immer mehr Beachtung fand, habe ich mich entschlossen, ihn zu erweitern und auf die anderen hervorragenden Lösungen zu verweisen, die hier veröffentlicht wurden. Mein ursprünglicher Post hatte eine Bemerkung, dass erwähnt , wenn Sie wurden auf Modifizieren Ihr Vektor in einer Absicht ,
for
Schleife , dann gibt es zwei , bereitgestellt durch Methodenstd::vector
zum Zugriffselement:std::vector::operator[]
die Grenzen nicht tun prüfen, undstd::vector::at
die tun ausführen Überprüfung Grenzen. Mit anderen Worten,at
wird geworfen, wenn Sie versuchen, auf ein Element außerhalb des Vektors zuzugreifen, undoperator[]
dies nicht tun würden. Ich habe diesen Kommentar ursprünglich nur hinzugefügt, um etwas zu erwähnen, von dem es nützlich sein könnte, zu wissen, ob dies bereits jemand getan hat. Und ich sehe jetzt keinen Unterschied. Daher dieser Nachtrag.quelle
0
durch durchlaufenvector::size()
und der Vektor innerhalb der Schleife nicht geändert wird, müssen Sie keinenat()
zusätzlichen Aufwand für die Überprüfung der Grenzen verwenden. Das heißt, ich würde mit einem Iterator gehen, wie Sie vorschlagen.at
wenn nichts in der Schleife ändert der Vektor, aber ich dachte , dass ich es nur für den Fall erwähnen würde der Vektor wird in der Schleife modifiziert (unrecommended wie das auch sein mag) , und weil es nie ein bekommt erwähnen und es könnte nützlich sein, zumindest davon zu wissen.for (auto const &i: path) std::cout << i << ' ';
Ein viel einfacherer Weg, dies zu tun, ist mit dem Standard- Kopieralgorithmus :
Der ostream_iterator ist ein sogenannter Iteratoradapter . Es wird über dem Typ angezeigt, der im Stream ausgedruckt werden soll (in diesem Fall
char
).cout
(auch bekannt als Konsolenausgabe) ist der Stream, in den wir schreiben möchten, und das Leerzeichen (" "
) ist das, was zwischen jedem im Vektor gespeicherten Element gedruckt werden soll.Dieser Standardalgorithmus ist leistungsstark und viele andere auch. Die Leistung und Flexibilität, die Ihnen die Standardbibliothek bietet, machen sie so großartig. Stellen Sie sich vor: Sie können mit nur einer Codezeile einen Vektor auf die Konsole drucken . Sie müssen sich nicht mit Sonderfällen mit dem Trennzeichen befassen. Sie müssen sich keine Sorgen um For-Loops machen. Die Standardbibliothek erledigt alles für Sie.
quelle
vector<pair<int, struct node>>
. Wie verwende ich die obige Methode, um diesen Vektor zu drucken?operator<<
Funktion für Ihr bestimmtes Paar deklarieren <>.In C ++ 11 können Sie jetzt eine bereichsbasierte for-Schleife verwenden :
quelle
char
s die Wahrscheinlichkeit, dass das Übergeben einer konstanten Referenz tatsächlich teurer ist als ein Wert. Aber hier sprechen wir von Super-Mikro-Optimierungen.Ich denke, der beste Weg, dies zu tun, besteht darin, einfach zu überladen,
operator<<
indem Sie diese Funktion zu Ihrem Programm hinzufügen:Dann können Sie den
<<
Operator für jeden möglichen Vektor verwenden, vorausgesetzt, seine Elemente haben auch Folgendesostream& operator<<
definiert:Ausgänge:
quelle
last
zusize_t
.size_t last = v.size() - 1;
sieht überflüssig aus, können Sieif (i) out << ", ";
Bedingung vor demout << v[i];
Link verwendenoperator<<
. Beispielif (i != last)
jedes Mal in der Schleife testen ? Stattdessen, wenn der Behälter nicht leer ist, dann (a) , um das erste Element zu senden, und dann (b) schlaufen senden und die restlichen Elemente den Separators Druck ersten (als Präfix). Es ist kein innerer Schleifentest (abgesehen von der Schleifenbedingung selbst) erforderlich. Es ist nur ein Out-of-Loop-Test erforderlich.Wie wäre es mit
for_each
+ Lambda-Ausdruck :Natürlich ein Range-basiertes für die konkreteste Lösung für diese konkrete Aufgabe, aber diese bietet auch viele andere Möglichkeiten.
Erläuterung
Der
for_each
Algorithmus verwendet einen Eingabebereich und ein aufrufbares Objekt und ruft dieses Objekt für jedes Element des Bereichs auf. Ein Eingabebereich wird durch zwei Iteratoren definiert . Ein aufrufbares Objekt kann eine Funktion, ein Zeiger auf eine Funktion, ein Objekt einer Klasse sein, die überladen ist,() operator
oder wie in diesem Fall ein Lambda-Ausdruck . Der Parameter für diesen Ausdruck entspricht dem Typ der Elemente aus dem Vektor.Das Schöne an dieser Implementierung ist die Leistung, die Sie durch Lambda-Ausdrücke erhalten. Sie können diesen Ansatz für viel mehr Dinge verwenden, als nur den Vektor zu drucken.
quelle
Kopieren Sie einfach den Container auf die Konsole.
Sollte ausgeben:
quelle
Das Problem liegt wahrscheinlich in der vorherigen Schleife :
(x = 17; isalpha(firstsquare); x++)
. Diese Schleife wird überhaupt nicht ausgeführt (wennfirstsquare
es sich nicht um Alpha handelt) oder für immer ausgeführt (wenn es sich um Alpha handelt). Der Grund ist, dass sichfirstsquare
das nicht ändert, wennx
es erhöht wird.quelle
In C ++ 11 ist eine bereichsbasierte for-Schleife möglicherweise eine gute Lösung:
Ausgabe:
quelle
Verwenden Sie
std::copy
jedoch ohne zusätzliches nachlaufendes TrennzeichenEin alternativer / modifizierter Ansatz mit
std::copy
(wie ursprünglich in der Antwort von @JoshuaKravtiz verwendet ), jedoch ohne ein zusätzliches nachfolgendes Trennzeichen nach dem letzten Element:Beispiel für die Verwendung eines Containers eines benutzerdefinierten POD-Typs:
quelle
Ich sehe zwei Probleme. Wie bereits erwähnt,
for (x = 17; isalpha(firstsquare); x++)
gibt es entweder eine Endlosschleife oder sie wird überhaupt nicht ausgeführt.if (entrance == 'S')
Wenn sich das Eingangszeichen von 'S' unterscheidet, wird nichts in den Pfadvektor verschoben, wodurch dieser leer wird und somit nichts auf dem Bildschirm gedruckt wird. Sie können letzteres testen, um zu prüfenpath.empty()
oder zu druckenpath.size()
.Wäre es nicht besser, einen String anstelle eines Vektors zu verwenden? Sie können wie ein Array auch auf den Inhalt der Zeichenfolge zugreifen, nach Zeichen suchen, Teilzeichenfolgen extrahieren und die Zeichenfolge einfach (ohne Schleife) drucken.
Wenn Sie alles mit Strings machen, können Sie es möglicherweise weniger kompliziert schreiben und das Problem leichter erkennen.
quelle
Überlastungsoperator <<:
Verwendungszweck:
quelle
Diese Antwort basiert auf der Antwort von Zorawar, aber ich konnte dort keinen Kommentar hinterlassen.
Sie können die automatische (C ++ 11) / typedef-Version const erstellen, indem Sie stattdessen cbegin und cend verwenden
quelle
In C ++ 11``
quelle
quelle
Das hat bei mir funktioniert:
quelle
Für diejenigen, die interessiert sind: Ich habe eine verallgemeinerte Lösung geschrieben, die das Beste aus beiden Welten nutzt, auf jeden Bereichstyp verallgemeinert ist und nicht arithmetische Typen in Anführungszeichen setzt (erwünscht für stringähnliche Typen). Darüber hinaus sollte dieser Ansatz keine ADL-Probleme aufweisen und auch „Überraschungen“ vermeiden (da er von Fall zu Fall explizit hinzugefügt wird):
Jetzt ist es ziemlich einfach in jedem Bereich zu verwenden:
Der stringartige Check lässt Raum für Verbesserungen. Ich habe auch
static_assert
meine Lösung eingechecktstd::basic_string<>
, um dies zu vermeiden , aber ich habe sie hier der Einfachheit halber weggelassen.quelle
Sie können Ihre eigene Funktion schreiben:
quelle
Für Leute, die Einzeiler ohne Schleifen wollen:
Ich kann nicht glauben, dass niemand daran gedacht hat, aber vielleicht liegt es an dem eher C-ähnlichen Ansatz. Wie auch immer, es ist absolut sicher, dies ohne eine Schleife in einem Einzeiler zu tun, vorausgesetzt , die
std::vector<char>
ist nullterminiert:Aber ich würde das in die einwickeln
ostream
Operator einwickeln, wie @Zorawar vorgeschlagen hat, nur um sicher zu gehen:Wir können ein ähnliches Verhalten erreichen, indem wir verwenden
printf
stattdessen verwenden:HINWEIS:
Der überladene
ostream
Operator muss den Vektor als nicht konstant akzeptieren. Dies kann das Programm unsicher machen oder missbräuchlichen Code einführen. Da ein Nullzeichen angehängt wird, kann es auch zu einer Neuzuweisung des Zeichensstd::vector
kommen. Die Verwendung von for-Schleifen mit Iteratoren wird daher wahrscheinlich schneller sein.quelle
fprintf(stdout, "%s\n", &test[0]);
sich nicht vonstd::cout << test.data()
, beide erfordern einen nullterminierten Vektor. 2. Der Operator "Aber ich würde dies in den Ostream-Operator einschließen"<<
, der den richtigen Operanden ändert, ist eine sehr schlechte Idee.fprintf(stdout, "%s\n", &test[0]);
lange Zeit Code verwendet, ohne dass es mir jemals Probleme bereitete. Interessant! Und ich stimme zu, dass es nicht so schön ist, den Vektor imostream
Operator zu ändern , aber ich mag es nicht, sowohl manuell zu schleifen als auch Iteratoren zu verwenden. Irgendwie habe ich das Gefühl, dass bei einfachen Vorgängen wie dem Drucken einestd::vector<char>
Standardbibliothek diese Dinge verstecken sollte. Aber C ++ entwickelt sich ständig weiter, es könnte bald kommen.