Koduję program, który czyta dane bezpośrednio z danych wejściowych użytkownika i zastanawiałem się, jak mogę (bez pętli) odczytać wszystkie dane do EOF ze standardowego wejścia. Rozważałem użycie, cin.get( input, '\0' )
ale '\0'
tak naprawdę nie jest to znak EOF, który czyta tylko do EOF lub '\0'
, cokolwiek nastąpi wcześniej.
A może używanie pętli jest jedynym sposobem na to? Jeśli tak, to jaki jest najlepszy sposób?
Korzystanie z pętli:
#include <iostream> using namespace std; ... // numbers int n; while (cin >> n) { ... } // lines string line; while (getline(cin, line)) { ... } // characters char c; while (cin.get(c)) { ... }
ratunek
źródło
Możesz to zrobić bez jawnych pętli, używając iteratorów strumienia. Jestem pewien, że wewnętrznie używa jakiejś pętli.
#include <string> #include <iostream> #include <istream> #include <ostream> #include <iterator> int main() { // don't skip the whitespace while reading std::cin >> std::noskipws; // use stream iterators to copy the stream to a string std::istream_iterator<char> it(std::cin); std::istream_iterator<char> end; std::string results(it, end); std::cout << results; }
źródło
Po zbadaniu rozwiązania KeithB przy użyciu
std::istream_iterator
, odkryłemstd:istreambuf_iterator
.Przetestuj program, aby wczytywał wszystkie dane wejściowe potokiem do łańcucha, a następnie wypisz go ponownie:
#include <iostream> #include <iterator> #include <string> int main() { std::istreambuf_iterator<char> begin(std::cin), end; std::string s(begin, end); std::cout << s; }
źródło
std::istreambuf_iterator
zamiast anstd::istream_iterator
, ale po co?Prawdopodobnie najprostszy i ogólnie skuteczny:
#include <iostream> int main() { std::cout << std::cin.rdbuf(); }
W razie potrzeby użyj tutaj strumienia innych typów, takich
std::ostringstream
jak bufor zamiast standardowego strumienia wyjściowego.źródło
std::ostringstream std_input; std_input << std::cin.rdbuf(); std::string s = std_input.str()
. masz wszystkie dane wejściowes
(uważaj,std::string
jeśli dane wejściowe są zbyt duże)Możesz użyć funkcji std :: istream :: getline () (lub najlepiej wersji, która działa na std :: string ), aby uzyskać cały wiersz. Obie mają wersje, które umożliwiają określenie separatora (znak końca wiersza). Wartość domyślna dla wersji ciągu to „\ n”.
źródło
Smutna uwaga: zdecydowałem się użyć C ++ IO, aby być spójnym z kodem opartym na boost. Z odpowiedzi na to pytanie wybrałem
while (std::getline(std::cin, line))
. Używając g ++ w wersji 4.5.3 (-O3) w Cygwin (Mintty) uzyskałem przepustowość 2 MB / s. Microsoft Visual C ++ 2010 (/ O2) zrobił 40 MB / s dla tego samego kodu.Po przepisaniu IO do czystego C
while (fgets(buf, 100, stdin))
przepustowość wzrosła do 90 MB / sw obu testowanych kompilatorach. To robi różnicę w przypadku każdego wejścia większego niż 10 MB ...źródło
std::ios::sync_with_stdio(false);
przed pętlą while.cin.tie(NULL);
może również pomóc, jeśli przeplatasz czytanie i pisanie.while(std::cin) { // do something }
źródło
// do something
nie zawiera dodatkowych kontroli zwracanych wartości operacji we / wy, a sprawdzenie, które zawiera, jest bez znaczenia.Czekaj, czy dobrze cię rozumiem? Używasz cin do wprowadzania danych z klawiatury i chcesz przestać czytać dane wejściowe, gdy użytkownik wprowadzi znak EOF? Dlaczego użytkownik miałby kiedykolwiek wpisywać znak EOF? A może chodziło Ci o to, że chcesz przestać czytać z pliku w EOF?
Jeśli faktycznie próbujesz użyć funkcji cin do odczytania znaku EOF, to dlaczego nie określić po prostu EOF jako separatora?
// Needed headers: iostream char buffer[256]; cin.get( buffer, '\x1A' );
Jeśli zamierzasz przestać czytać z pliku w EOF, po prostu użyj getline i jeszcze raz określ EOF jako separator.
// Needed headers: iostream, string, and fstream string buffer; ifstream fin; fin.open("test.txt"); if(fin.is_open()) { getline(fin,buffer,'\x1A'); fin.close(); }
źródło
Jedną z opcji jest użycie pojemnika, np
std::vector<char> data;
i przekieruj wszystkie dane wejściowe do tej kolekcji, dopóki nie
EOF
zostaną odebrane, tjstd::copy(std::istream_iterator<char>(std::cin), std::istream_iterator<char>(), std::back_inserter(data));
Jednak używany kontener może wymagać zbyt częstego ponownego przydzielania pamięci lub zakończy się
std::bad_alloc
wyjątkiem, gdy w systemie zabraknie pamięci. Aby rozwiązać te problemy, można zarezerwować określoną liczbęN
elementów i przetworzyć te ilości oddzielnie, tjdata.reserve(N); while (/*some condition is met*/) { std::copy_n(std::istream_iterator<char>(std::cin), N, std::back_inserter(data)); /* process data */ data.clear(); }
źródło