Урок №208. Функционал класса istream

  Юрий  | 

  |

  Обновл. 15 Сен 2021  | 

 42605

 ǀ   2 

Библиотека iostream по своей сути довольно сложная, поэтому мы не сможем охватить её полностью в рамках данных уроков. Тем не менее, мы можем рассмотреть её основной функционал. На этом уроке мы разберемся с классом istream.

Примечание: Весь функционал объектов, которые работают с потоками ввода/вывода, находится в пространстве имен std. Это означает, что вам нужно либо добавлять префикс std:: ко всем объектам и функциям ввода/вывода, либо использовать строку using namespace std;.

Оператор извлечения

Как вы уже узнали на предыдущем уроке, мы можем использовать оператор извлечения >> для считывания информации из входного потока. Одной из наиболее распространенных проблем при считывании строк из входного потока является предотвращение переполнения. Например:

Что произойдет, если пользователь введет 20 символов? Правильно, переполнение. Одним из способов решения этой проблемы является использование манипуляторов. Манипулятор — это объект, который применяется для изменения потока данных с использованием операторов извлечения (>>) или вставки (<<).

Мы уже работали с одним из манипуляторов — endl, который одновременно выводит символ новой строки и удаляет текущие данные из буфера. Язык C++ предоставляет еще один манипулятор — setw() (из заголовочного файла iomanip), который используется для ограничения количества символов, считываемых из потока. Для использования setw() вам нужно просто передать в качестве параметра максимальное количество символов для извлечения и вставить вызов этого манипулятора следующим образом:

Эта программа теперь прочитает только первые 11 символов из входного потока (+ один символ для нуль-терминатора). Все остальные символы останутся в потоке до следующего извлечения.

Извлечение и пробелы


Важный момент: оператор извлечения работает с «отформатированными» данными, т.е. он игнорирует все пробелы, символы табуляции и символ новой строки. Например:

Если пользователь введет следующее:

Hello! My name is Anton

То оператор извлечения пропустит все пробелы и символы новой строки. Следовательно, результат выполнения программы:

Hello!MynameisAnton

Часто пользовательский ввод все же нужен со всеми его пробелами. Для этого класс istream предоставляет множество функций. Одной из наиболее полезных является фунция get(), которая извлекает символ из входного потока. Вот вышеприведенная программа, но уже с использованием функции get():

Теперь, если мы введем следующее:

Hello! My name is Anton

То получим:

Hello! My name is Anton

Функция get() также имеет строковую версию, в которой можно указать максимальное количество символов для извлечения. Например:

Если мы введем следующее:

Hello! My name is Anton

То получим:

Hello! My n

Обратите внимание, программа считывает только первые 11 символов (+ нуль-терминатор). Остальные символы остаются во входном потоке.

Один важный нюанс: функция get() не считывает символ новой строки! Например:

Если пользователь введет следующее:

Hello!

То получит:

Hello!

И программа сразу же завершит свое выполнение! Почему так? Почему не срабатывает второй ввод данных? Дело в том, что первый get() считывает символы до символа новой строки, а затем останавливается. Второй get() видит, что во входном потоке все еще есть данные и пытается их извлечь. Но первый символ, на который он натыкается — символ новой строки, поэтому происходит второй «Стоп!».

Для решения данной проблемы класс istream предоставляет функцию getline(), которая работает точно так же, как и функция get(), но при этом может считывать символы новой строки:

Этот код работает точно так, как ожидается, даже если пользователь введет строку с символом новой строки.

Если вам нужно узнать количество символов, извлеченных последним getline(), используйте функцию gcount():

Результат:

Hello! My name is Anton
24 characters were read

Специальная версия функции getline() для std::string

Есть специальная версия функции getline(), которая находится вне класса istream и используется для считывания переменных типа std::string. Она не является членом ни ostream, ни istream, а подключается заголовочным файлом string. Например:

Еще несколько полезных функций класса istream


Есть еще несколько полезных функций класса istream, которые вы можете использовать:

   функция ignore() — игнорирует первый символ из потока;

   функция ignore(int nCount) — игнорирует первые nCount (количество) символов из потока;

   функция peek() — считывает символ из потока, при этом не удаляя его из потока;

   функция unget() — возвращает последний считанный символ обратно в поток, чтобы его можно было извлечь в следующий раз;

   функция putback(char ch) — помещает выбранный вами символ обратно в поток, чтобы его можно было извлечь в следующий раз.

Класс istream содержит еще множество других полезный функций и их вариаций, но это уже тема для отдельного туториала.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (136 оценок, среднее: 4,89 из 5)
Загрузка...

Комментариев: 2

  1. Duke:

    День добрый!
    Работаю в реплите.
    Не понимаю слегка как работает в вашем примере getline, когда вписываю 12 символов в поток первый раз, второй раз гетлайн уже не выполняется и программа завершается, хоть первый раз гетлайн и выводит 11 символов в ch, где 12 это нуль терминатор разумеется, однако…
    Если вводить 11 символов то второй раз getline выполняется.

    Вопрос: Почему и как это работает в данном примере?

    1. Александр:

      у меня эта проблема решилась только так
      чуть-чуть кода пока пробовал по-разному сделать

Добавить комментарий для Duke Отменить ответ

Ваш E-mail не будет опубликован. Обязательные поля помечены *