Chcę wydrukować zawartość wektora w C ++, oto co mam:
#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;
}
}
Jak wydrukować zawartość wektora na ekranie?
Odpowiedzi:
Aby odpowiedzieć na twoje pytanie, możesz użyć iteratora:
Jeśli chcesz zmodyfikować zawartość wektora w pętli for, użyj
iterator
raczej niżconst_iterator
.Ale jest o wiele więcej do powiedzenia na ten temat. Jeśli chcesz tylko odpowiedzi, której możesz użyć, możesz zatrzymać się tutaj; w przeciwnym razie czytaj dalej.
auto (C ++ 11) / typedef
To nie jest kolejne rozwiązanie, ale uzupełnienie powyższego
iterator
rozwiązania. Jeśli używasz standardu C ++ 11 (lub nowszego), możesz użyćauto
słowa kluczowego, aby poprawić czytelność:Ale typem
i
będzie non-const (tzn. Kompilator użyjestd::vector<char>::iterator
jako typui
).W takim przypadku możesz równie dobrze użyć
typedef
(nie ograniczonego do C ++ 11 i bardzo przydatnego w każdym razie):licznik
Możesz oczywiście użyć typu liczby całkowitej, aby zapisać swoją pozycję w
for
pętli:Jeśli masz zamiar to zrobić, lepiej użyć typów członków kontenera, jeśli są one dostępne i odpowiednie.
std::vector
ma typ członka wywołanysize_type
dla tego zadania: jest to typ zwracany przezsize
metodę.Dlaczego nie wykorzystać tego zamiast
iterator
rozwiązania? W prostych przypadkach równie dobrze możesz, ale chodzi o to, żeiterator
klasa jest obiektem zaprojektowanym do wykonywania tego zadania w przypadku bardziej skomplikowanych obiektów, w których to rozwiązanie nie będzie idealne.oparte na zakresie dla pętli (C ++ 11)
Zobacz rozwiązanie Jefffreya . W C ++ 11 (i nowszych) możesz użyć nowej
for
pętli opartej na zakresie , która wygląda następująco:Ponieważ
path
jest wektorem elementów (jawniestd::vector<char>
), obiekti
jest typu elementu wektora (tj. Jawnie jest typuchar
). Obiekti
ma wartość będącą kopią faktycznego elementu wpath
obiekcie. Dlatego wszystkie zmianyi
w pętli nie są zachowanepath
same w sobie. Dodatkowo, jeśli chcesz, aby wymusić na fakt, że nie chcesz, aby móc zmienić skopiowane wartościi
w pętli, można wymusić typi
byćconst char
tak:Jeśli chcesz zmodyfikować elementy
path
, możesz użyć odwołania:a nawet jeśli nie chcesz modyfikować
path
, jeśli kopiowanie obiektów jest drogie, powinieneś użyć stałego odwołania zamiast kopiowania według wartości:std :: kopia
Zobacz odpowiedź Jozuego . Za pomocą algorytmu STL
std::copy
można skopiować zawartość wektora do strumienia wyjściowego. Jest to eleganckie rozwiązanie, jeśli czujesz się z nim komfortowo (a poza tym jest bardzo przydatne, nie tylko w tym przypadku drukowania zawartości wektora).std :: for_each
Zobacz rozwiązanie Maxa . Używanie
std::for_each
jest przesadą w tym prostym scenariuszu, ale jest to bardzo przydatne rozwiązanie, jeśli chcesz zrobić więcej niż tylko drukowanie na ekranie: użyciestd::for_each
pozwala na wykonanie dowolnej (sensownej) operacji na zawartości wektorowej.przeciążenie ostream :: operator <<
Zobacz odpowiedź Chrisa , jest to bardziej uzupełnienie innych odpowiedzi, ponieważ nadal będziesz musiał wdrożyć jedno z powyższych rozwiązań w przypadku przeciążenia. W swoim przykładzie użył licznika w
for
pętli. Na przykład w ten sposób możesz szybko użyć rozwiązania Jozuego :Korzystanie z innych rozwiązań powinno być proste.
wniosek
Każde z przedstawionych tutaj rozwiązań będzie działać. To zależy od Ciebie i od tego, który kod jest „najlepszy”. Wszystko, co jest bardziej szczegółowe niż to, jest prawdopodobnie najlepiej pozostawić w innym pytaniu, w którym zalety / wady można odpowiednio ocenić; ale jak zawsze preferencje użytkownika zawsze będą odgrywać rolę: żadne z przedstawionych rozwiązań nie jest złe, ale niektóre będą ładniejsze dla każdego kodera.
uzupełnienie
To jest rozwinięte rozwiązanie wcześniejszego, które opublikowałem. Ponieważ ten post wciąż cieszył się zainteresowaniem, postanowiłem go rozwinąć i odnieść się do innych doskonałych rozwiązań, które zostały tutaj opublikowane. Mój oryginalny post miał uwagę, że wspomniany, że jeśli były zamierzający na zmodyfikowanie wektor wewnątrz
for
pętli następnie istnieją dwie metody przewidzianestd::vector
do elementów dostępu:std::vector::operator[]
który nie robi granice kontroli, astd::vector::at
który ma wykonać sprawdzanie ograniczeń. Innymi słowy,at
wyrzuci, jeśli spróbujesz uzyskać dostęp do elementu poza wektorem ioperator[]
nie zrobi tego. Pierwotnie dodałem ten komentarz tylko po to, by wspomnieć o czymś, co może być przydatne, jeśli ktoś już tego nie zrobił. I nie widzę teraz żadnej różnicy. Stąd to uzupełnienie.źródło
0
przechodzi przezvector::size()
i wektor nie jest modyfikowany w pętli, nie ma potrzeby używaniaat()
i ponoszenia dodatkowych ograniczeń sprawdzania narzutu. To powiedziawszy, wybrałbym iterator, jak sugerujesz.at
jeśli nic w pętli nie modyfikuje wektora, ale pomyślałem, że wspomnę o tym na wypadek, gdyby wektor został zmodyfikowany w pętli (może to być niezalecane) i ponieważ nigdy nie dostaje wspomnieć i może być przydatna, przynajmniej o tym wiedzieć.for (auto const &i: path) std::cout << i << ' ';
Znacznie łatwiejszym sposobem na to jest standardowy algorytm kopiowania :
Ostream_iterator to tak zwany adapter iteratora . Jest on wzorowany na typie, aby wydrukować do strumienia (w tym przypadku,
char
).cout
(aka wyjście konsoli) to strumień, do którego chcemy pisać, a znak spacji (" "
) jest tym, co chcemy wydrukować między każdym elementem przechowywanym w wektorze.Ten standardowy algorytm jest potężny, podobnie jak wiele innych. Moc i elastyczność, jaką zapewnia standardowa biblioteka, sprawiają, że jest ona tak wspaniała. Wyobraź sobie: możesz wydrukować wektor na konsoli za pomocą tylko jednego wiersza kodu. Nie musisz zajmować się specjalnymi przypadkami ze znakiem separatora. Nie musisz się martwić o pętle for. Standardowa biblioteka robi to wszystko za Ciebie.
źródło
vector<pair<int, struct node>>
. Jak użyć powyższej metody, aby wydrukować ten wektor?operator<<
funkcję dla określonej pary <>.W C ++ 11 możesz teraz używać pętli bazującej na zakresie :
źródło
char
s istnieje prawdopodobieństwo, że przejście przez stałe odniesienie jest w rzeczywistości bardziej kosztowne niż wartość. Ale tutaj mówimy o super mikrooptymalizacjach.Myślę, że najlepszym sposobem na to jest po prostu przeciążenie
operator<<
, dodając tę funkcję do swojego programu:Następnie możesz użyć
<<
operatora na dowolnym możliwym wektorze, zakładając, że jego elementy również mająostream& operator<<
zdefiniowane:Wyjścia:
źródło
last
nasize_t
.size_t last = v.size() - 1;
wygląda na zbędny, możesz użyćif (i) out << ", ";
warunku przedout << v[i];
linkiemoperator<<
. Przykładif (i != last)
co testować za każdym razem w pętli? Zamiast tego, jeśli pojemnik nie jest pusty, to (a) wyślij pierwszy element, a następnie (b) wyślij pętlę pozostałe elementy, drukując najpierw separator (jako przedrostek). Nie jest wymagany test pętli wewnętrznej (oprócz samego stanu pętli). Wymagany jest tylko jeden test poza pętlą.Co powiesz na
for_each
wyrażenie + lambda :Oczywiście oparte na zakresie jest najbardziej eleganckim rozwiązaniem dla tego konkretnego zadania, ale to daje także wiele innych możliwości.
Wyjaśnienie
for_each
Algorytm bierze zakres wejściowy i wpłacone obiekt , nazywając ten obiekt na każdym elemencie zakresie. Zakres wejściowy jest utworzony przez dwie iteratorami . Obiekt wywoływalny może być funkcją, wskaźnikiem funkcji, obiektem klasy, która się przeciąża() operator
lub, jak w tym przypadku, wyrażeniem lambda . Parametr tego wyrażenia odpowiada typowi elementów z wektora.Piękno tej implementacji polega na sile, jaką czerpiesz z wyrażeń lambda - możesz użyć tego podejścia do znacznie więcej rzeczy niż tylko do drukowania wektora.
źródło
Po prostu skopiuj kontener do konsoli.
Powinien generować:
źródło
Problem jest prawdopodobnie w poprzedniej pętli:
(x = 17; isalpha(firstsquare); x++)
. Ta pętla w ogóle nie będzie działać (jeślifirstsquare
nie jest alfa) lub będzie działać wiecznie (jeśli jest alfa). Powodem jest to, żefirstsquare
nie zmienia się, ponieważx
jest zwiększana.źródło
W C ++ 11 dobrym rozwiązaniem może być oparte na zakresie pętla:
Wynik:
źródło
Używanie,
std::copy
ale bez dodatkowego separatora końcowegoAlternatywne / zmodyfikowane podejście wykorzystujące
std::copy
(jak pierwotnie użyto w odpowiedzi @JoshuaKravtiz ), ale bez dodatkowego separatora końcowego po ostatnim elemencie:Przykładowe użycie zastosowane do kontenera niestandardowego typu POD:
źródło
przeciążenie operatora <<:
Stosowanie:
źródło
Widzę dwa problemy. Jak wskazano w,
for (x = 17; isalpha(firstsquare); x++)
istnieje albo nieskończona pętla, albo nigdy w ogóle nie jest wykonywana, a takżeif (entrance == 'S')
jeśli znak wejściowy jest inny niż „S”, wówczas nic nie jest wypychane do wektora ścieżki, co czyni go pustym, a tym samym nie drukuje niczego na ekranie. Możesz przetestować to drugie, sprawdzającpath.empty()
lub drukującpath.size()
.Tak czy inaczej, czy nie lepiej byłoby użyć łańcucha zamiast wektora? Możesz uzyskać dostęp do zawartości łańcucha, jak również tablicy, wyszukiwać znaki, wyodrębniać podciągi i łatwo drukować ciąg (bez pętli).
Wykonanie tego wszystkiego za pomocą łańcuchów może być sposobem na napisanie go w mniej skomplikowany sposób i łatwiejsze dostrzeżenie problemu.
źródło
Ta odpowiedź oparta jest na odpowiedzi Zorawara, ale nie mogłem tam zostawić komentarza.
Możesz ustawić wersję automatyczną (C ++ 11) / typedef const za pomocą cbegin i cend zamiast tego
źródło
W C ++ 11 ''
źródło
źródło
To działało dla mnie:
źródło
Dla tych, którzy są zainteresowani: napisałem uogólnione rozwiązanie, które bierze to, co najlepsze z obu światów, jest bardziej uogólnione na dowolny typ zakresu i umieszcza cudzysłowy wokół typów nie arytmetycznych (pożądane dla typów łańcuchowych). Co więcej, to podejście nie powinno mieć żadnych problemów z ADL, a także unikać „niespodzianek” (ponieważ jest dodawane wyraźnie w poszczególnych przypadkach):
Teraz jest dość łatwy w użyciu w dowolnym zakresie:
Sznurkowy czek pozostawia pole do poprawy. Mam również
static_assert
rozwiązanie w celu uniknięciastd::basic_string<>
, ale zostawiłem to tutaj dla uproszczenia.źródło
Możesz napisać własną funkcję:
źródło
Dla osób, które chcą jednowarstwowe bez pętli:
Nie mogę uwierzyć, że nikt o tym nie pomyślał, ale być może wynika to z bardziej podobnego do C podejścia. W każdym razie jest to całkowicie bezpieczne, bez pętli, w jednej linijce , PRZYJMUJĄC, że
std::vector<char>
jest ona zakończona zerem:Ale chciałbym owinąć to w
ostream
operatora, jak sugerował @Zorawar, dla bezpieczeństwa:Podobne zachowanie możemy osiągnąć, stosując w
printf
zamian:UWAGA:
Przeciążony
ostream
operator musi zaakceptować wektor jako non-const. Może to spowodować, że program będzie niepewny lub wprowadzi błędny kod. Ponadto, ponieważ dodawany jest znak zerowy,std::vector
może nastąpić realokacja . Używanie pętli for z iteratorami będzie prawdopodobnie szybsze.źródło
fprintf(stdout, "%s\n", &test[0]);
nie różni się odstd::cout << test.data()
, oba wymagają wektora zakończonego zerem. 2. „Ale owinąłbym to w operator ostream”<<
, który modyfikuje odpowiedni operand, to bardzo zły pomysł.fprintf(stdout, "%s\n", &test[0]);
od dłuższego czasu w kodzie, nie sprawiając mi żadnych problemów. Ciekawy! I zgadzam się, że modyfikowanie wektora wostream
operatorze nie jest tak miłe , ale nie podoba mi się zarówno ręczne zapętlanie, jak i używanie iteratorów. Jakoś mam wrażenie, że proste operacje, takie jak wydrukstd::vector<char>
standardowej biblioteki, powinny ukryć te rzeczy. Ale C ++ stale się rozwija, może wkrótce.