Biblioteka iostream jest dość złożona — dlatego nie będziemy w stanie omówić jej w swojej formie w całości w tych tutorialach. Pokażemy Ci jednak najczęściej używane funkcjonalności. W tej sekcji przyjrzymy się różnym aspektom klasy wejściowej (istream).
Operator ekstrakcji
Jak widzieliśmy w wielu lekcjach, możemy użyć operatora ekstrakcji (>>) do odczytania informacji ze strumienia wejściowego. C++ ma predefiniowane operacje ekstrakcji dla wszystkich wbudowanych typów danych i już widziałeś, jak przeciążyć operator ekstrakcji dla własnych klas.
Podczas odczytywania ciągów znaków częstym problemem związanym z operatorem wyodrębniania jest to, jak zapobiec przepełnieniu bufora danych wejściowych. Biorąc pod uwagę następujący przykład:
char buf[10]{};
std::cin >> buf;co się stanie, jeśli użytkownik wprowadzi 18 znaków? Bufor się przepełnia i dzieją się złe rzeczy. Ogólnie rzecz biorąc, nie należy zakładać, ile znaków wprowadzi użytkownik.
Jednym ze sposobów rozwiązania tego problemu jest użycie manipulatorów. Manipulator manipulator to obiekt służący do modyfikacji strumienia po zastosowaniu operatorów ekstrakcji (>>) lub wstawienia (<<). Jednym z manipulatorów, z którym już pracowałeś, jest „std::endl”, który zarówno wypisuje znak nowej linii, jak i opróżnia buforowane dane wyjściowe. C++ udostępnia manipulator znany jako setw (w nagłówku iomanip), którego można użyć do ograniczenia liczby znaków odczytywanych ze strumienia. Aby użyć setw(), po prostu podaj maksymalną liczbę znaków do odczytania jako parametr i wstaw ją do instrukcji wejściowej w następujący sposób:
#include <iomanip>
char buf[10]{};
std::cin >> std::setw(10) >> buf;Ten program będzie teraz czytał tylko pierwsze 9 znaków ze strumienia (pozostawiając miejsce na terminator). Wszelkie pozostałe znaki pozostaną w strumieniu aż do następnej ekstrakcji.
Wyodrębnianie i białe znaki
Dla przypomnienia operator wyodrębniania pomija białe znaki (spacje, tabulatory i znaki nowej linii).
Spójrz na następujący program:
int main()
{
char ch{};
while (std::cin >> ch)
std::cout << ch;
return 0;
}Gdy użytkownik wprowadzi następujące informacje:
Hello my name is Alex
Operator wyodrębniania pomija spacje i nowa linia. W związku z tym wynik jest następujący:
HellomynameisAlex
Często będziesz chciał uzyskać dane wejściowe użytkownika, ale nie usuwać białych znaków. Aby to zrobić, klasa istream udostępnia wiele funkcji, które można w tym celu wykorzystać.
Jedną z najbardziej przydatnych jest funkcja get() , która po prostu pobiera znak ze strumienia wejściowego. Oto ten sam program, co powyżej, wykorzystujący metodę get():
int main()
{
char ch{};
while (std::cin.get(ch))
std::cout << ch;
return 0;
}Teraz, gdy użyjemy wejścia:
Hello my name is Alex
Wyjście będzie następujące:
Hello my name is Alex
get() ma również wersję łańcuchową, która wymaga maksymalnej liczby znaków do odczytania:
int main()
{
char strBuf[11]{};
std::cin.get(strBuf, 11);
std::cout << strBuf << '\n';
return 0;
}Jeśli wprowadzimy:
Hello my name is Alex
Wyjście będzie następujące:
Hello my n
Zauważ, że czytamy tylko pierwsze 10 znaków (musieliśmy zostawić jeden znak dla terminatora). Pozostałe znaki pozostały w strumieniu wejściowym.
Jedną ważną rzeczą, na którą należy zwrócić uwagę w przypadku funkcji get() jest to, że nie czyta ona znaku nowej linii! Może to spowodować nieoczekiwane rezultaty:
int main()
{
char strBuf[11]{};
// Read up to 10 characters
std::cin.get(strBuf, 11);
std::cout << strBuf << '\n';
// Read up to 10 more characters
std::cin.get(strBuf, 11);
std::cout << strBuf << '\n';
return 0;
}Jeśli użytkownik wprowadzi:
Hello!
Program wydrukuje:
Hello!
a następnie zakończy działanie! Dlaczego nie poprosiło o 10 dodatkowych znaków? Odpowiedź jest taka, że pierwsza funkcja get() odczytała znak nowej linii, a następnie zatrzymała się. Druga funkcja get() zobaczyła, że w strumieniu cin nadal znajdują się dane wejściowe, i próbowała je odczytać. Ale pierwszym znakiem był znak nowej linii, więc działanie natychmiast się zatrzymało.
W rezultacie istnieje inna funkcja o nazwie getline() , która działa podobnie do get(), ale wyodrębni (i odrzuci) ogranicznik.
int main()
{
char strBuf[11]{};
// Read up to 10 characters
std::cin.getline(strBuf, 11);
std::cout << strBuf << '\n';
// Read up to 10 more characters
std::cin.getline(strBuf, 11);
std::cout << strBuf << '\n';
return 0;
}Ten kod będzie działał zgodnie z oczekiwaniami, nawet jeśli użytkownik wprowadzi ciąg znaków ze znakiem nowej linii.
Jeśli chcesz wiedzieć, ile znaków zostało wyodrębnionych przez ostatnie wywołanie funkcji getline(), użyj gcount():
int main()
{
char strBuf[100]{};
std::cin.getline(strBuf, 100);
std::cout << strBuf << '\n';
std::cout << std::cin.gcount() << " characters were read" << '\n';
return 0;
}gcount() zawiera wszystkie wyodrębnione i odrzucone ograniczniki.
Specjalna wersja getline() dla std::string
Istnieje specjalna wersja getline(), która znajduje się poza klasą istream i jest używana do odczytu w zmiennych typu std::string. Ta specjalna wersja nie należy do ani ostream, ani istream i jest zawarta w nagłówku ciągu znaków. Oto przykład jego użycia:
#include <string>
#include <iostream>
int main()
{
std::string strBuf{};
std::getline(std::cin, strBuf);
std::cout << strBuf << '\n';
return 0;
}Kilka bardziej przydatnych funkcji istream
Jest jeszcze kilka przydatnych funkcji wejściowych, z których możesz chcieć skorzystać:
ignore() odrzuca pierwszy znak w strumieniu.
ignore(int nCount) odrzuca pierwszy nCount znaków.
peek() umożliwia odczytanie znaku ze strumienia bez usuwania go ze strumienia.
unget() zwraca ostatni odczytany znak z powrotem do strumienia, dzięki czemu można go ponownie odczytać przy następnym wywołaniu.
putback(char ch) umożliwia wstawienie znaku według własnego wyboru z powrotem do strumienia, aby można go było przeczytać podczas następnego wywołania.
istream zawiera wiele innych funkcji i wariantów wyżej wymienionych funkcji, które mogą być przydatne, w zależności od tego, co musisz zrobić. Można je znaleźć w witrynie referencyjnej, takiej jak https://en.cppreference.com/w/cpp/io/basic_istream.

