Потоки

1.  Система ввода-вывода С++

Встроенных средств ввода/вывода в С/С++ нет. Так как проектирование и реализация средств универсального ввода/вывода задача нетривиальная (так как связана и с аппаратурой, и с ОС), с самого начала существования С программисту предоставлялись средства (функции стандартной библиотеки: printf() и scanf() - <stdio.h> - streams) для ввода/вывода базовых типов данных (только). В С, наверно, этого было достаточно, но с появлением и развитием С++ основной задачей программиста стало создание собственных пользовательских типов, поэтому:

1)  появился и новый стиль ввода/вывода – объектно-ориентированный

2)  главной задачей при создании новых средств ввода/вывода было унифицировать эти операции:– то есть
а) операция должна выглядеть одинаково как применительно к базовым, так и пользовательским типам.=> Главным преимуществом системы ввода/вывода С++ является то, что операции могут перегружаться для создаваемых Вами пользовательских классов. Это отличие позволяет легко встраивать в систему ввода/вывода С++ новые, создаваемые Вами типы данных.
б) операция должна выглядеть одинаково – выводите ли Вы на экран или в файл.

3)  Сервисы ввода/вывода в С++ были переработаны таким образом, чтобы учесть как б), так и а). В стандартизованном С++ предоставляются программисту посредством подключения заголовочного файла <iostream>.

Замечания:

1)  в С++ поддерживается вся система ввода/вывода С. Но смешивать не стоит – если один символ выводится потоковой функцией, а другой с помощью putc(), то порядок их появления на экране не гарантируется.

НЕ нашли? Не то? Что вы ищете?

2)  на данный момент времени существуют две версии библиотеки потоков ввода/вывода С++: старая, основанная на изначальной спецификации С++ (iostream. h), и новая, определенная единым международным стандартом С++ (iostream). С точки зрения программиста для решения подавляющего большинства задач обе эти библиотеки идентичны. Так происходит потому, что новая библиотека – это по существу просто обновленная и усовершенствованная версия старой. Фактически почти все отличия скрыты от Вас в реализации (а не в способе использования). Для программиста существенным отличием является ряд дополнительных возможностей и несколько новых типов данных. Поскольку старая версия считается устаревшей, рекомендуется пользоваться только новой библиотекой.

3)  как и в С, в системе объектно-ориентированного ввода/вывода С++ имеется незначительная разница между консольным и файловым вводом/выводом. На самом деле, консольный и файловый ввод/вывод поддерживаются одним и тем же базовым классом, поэтому – это просто разный взгляд на один и тот же механизм.

4)  Вы можете использовать классы iostream и при создании Windows-приложений. При этом учитывайте, что все, что связано с преобразованием строк и файловый ввод/вывод работают без ограничений, но то, что связано с выводом на консоль – несовместимы с графическим интерфейсом Windows.

В примерах мы уже пользовались стилем ввода/вывода С++. Например:

#include <iostream>

{

int num;

std::cin>>num;

}

Теперь настало время использовать ввод/вывод сознательно.

2.  Что такое поток С++.

Программа оперирует со значениями, пользователь хочет видеть информацию в символьном виде => неизбежно требуются способы преобразования и вывода (на экран, в файл…) и ввода.

2.1.  С точки зрения системы

Вы можете представлять себе поток как «smart» файл, который является источником или получателем байтов Ваших данных.

Посредством драйверов устройств DOS общается с клавиатурой, экраном, принтером и коммуникационными портами как с некоторым логическим устройством (extended файлами в памяти). А классы ввода/вывода в свою очередь умеют взаимодействовать с этими логическими устройствами. Встроенная в классы поддержка позволяет читать и писать в память также как и на диск.

Поток ввода/вывода – это совокупность средств, которая выдает и принимает пользовательскую информацию. Но система «видит» только логическое устройство, а программист «видит» только класс => программист

1)  изолирован от реализации ввода/вывода.

2)  Поскольку все потоки ввода/вывода действуют одинаково, то, несмотря на то, что программисту приходится работать с совершенно разными по характеристикам устройствами, система ввода/вывода предоставляет для этого единый удобный интерфейс. Например, функция, которая используется для вывода на экран монитора, также подойдет для записи в файл или для вывода на принтер.

2.2.  С точки зрения программиста (прикладной программы)

2.2.1.  Классы ввода/вывода

MSDN|iostream Class List

Потоки ввода/вывода представляют собой объекты классов, предоставляемых стандартной библиотекой. Иерархия классов ввода/вывода сложна.

Замечание: на самом деле библиотека ввода/вывода создает две отдельные версии иерархий классов: одну для 8-разрядных символов и другую для «широких» символов, поэтому часть является на самом деле шаблонами классов. Для стандартных 8-разрядных символов эту иерархию в упрощенном виде можно было бы представить: Шилдт – 243

ios – специализация шаблона basic_ios для 8-разрядных символов. Базовый класс – можно считать абстрактным, так как программист не создает объекты этого класса и не наследует непосредственно от этого класса свои классы. Контролирует: 1) форматирование, 2) локализацию – национальные особенности, 3) обращение к буферам.

The cin object is a predefined object of class ostream_withassign. It is connected to stdin (standard input, file descriptor 0).

2.2.2.  Классы, предназначенные для использования программистом

Вы можете пользоваться для ввода: istream (стандартный объект cin – предоставляется по умочанию), ifstream (файловый ввод/вывод – создается по мере надобности программистом), istrstream (для работы со строками “-“).

Для вывода: ostream, ofstream, ostrstream/

2.2.3.  Стандартные объекты

Когда запускается программа на С++, автоматически открываются четыре потока: это означает следующее:

1)  Можно считать, что объекты – глобальные и создаются в прологе программы, на самом деле все обстоит несколько иначе – для повышения эффективности (если Вы вообще не пользуетесь вводом/выводом, то незачем и создавать объекты.) – аналогия с локальными статическими объектами

в прологе программы (перед тем, как вызывается функция main) работает стартовый код Run-Time Library, который в частности конструирует все Ваши глобальные объекты, в том числе создет единственный статический объект вспомогательного класса Iostream_init в ответ на первое обращение в программе к любому из объектов cin, cout, cerr, clog (w???), который в свою очередь создает и инициализирует эти объекты. (Это делает библиотека Run-Time Library без Вашего ведома и сами Вы объект Iostream_init никогда не создаете).

2)  в каждой единице компиляции Вы можете пользоваться этими объектами,
а) подключив заголовочный файл <iostream>
б) но в этом файле все объявления заключены в пространство имен std, поэтому для использования объектов – std:: или using

namespace std {

extern istream cin;

extern ostream cout;

extern ostream cerr;

extern ostream clog;

extern wistream wcin;

extern wostream wcout;

extern wostream wcerr;

extern wostream wclog;

};

3)  в эпилоге вызываются деструкторы

Замечание: пользуясь в MFC-приложениях потоками ввода/вывода, Вы можете увидеть диагностику «Memory leaks» - это происходит потому, что объекты потоков разрушаются позже, чем выдается эта диагностика.

Потоки для стандартных 8-разрядных символов

Потоки для расширенных символов (16-разрядных)

Предназначен

Устройство по умолчанию

istream cin

wistream wcin

Стандартный ввод

клавиатура

ostream cout

wostream wcout

Стандартный вывод

экран

ostream cerr

wostream wcerr

Стандартная ошибка (небуферизованная)

экран

ostream clog

wostream wclog

Буферизуемая версия cerr

экран

Замечание: - потоки cin, cout, cerr соответствуют: stdin, stdout и stderr.

2.3.  Буферизованный ввод/вывод

1) Вывод:

В приложении (во всяком случае, разработанном на Microsoft C/C++) поток вывода буферизован: (Страуструп 708). Буферизацию обеспечивает встроенный объект класса streambuf:

это означает, что данные, отправленные в поток вывода, могут не появиться на экране, пока буфер вывода не будет очищены (flushed). Существуют следующие способы для того, чтобы заставить поток вывода немедленно вывести содержимое буфера на экран:

1. использовать манипулятор cout<<…<<endl; //не только вставляет ‘\n’, но и очищает буфер (то есть отправляет его содержимое в реальный приемник),

2. использовать специальный метод класса: cout. flush();

3. существует также flush-манипулятор: cout<<flush;

4. чтение из потока ввода принудительно очищает буфер вывода (так как поток ввода и поток вывода «делят» один и тот же буфер, вызов любого из них очищает содержимое буфера перед тем, как делать какие-нибудь изменения)

5. exit очищает все буферы

The objects cin, cerr, and clog are tied to cout so that use of any of these may cause cout to be flushed.

2) Ввод

Тоже буферизован, но (к сожалению) явной возможности его «сбросить» (типа flush) у Вас нет. Поэтому хорошо, когда пользователь вводит то, что поток от него ожидает или может преобразовать к ожидаемому:

double d;

cin>>d; //1) 2 – преобразуется к d=2.0
2) 2A – d=2.0 – значение сформировано, но «А» еще осталось в буфере потока и ждет приема char
3) 3,3 вместо 3.3 - d=3.0, но запятая и вторая 3 осталась в буфере ввода и ждет ввода
4) вводим AAA - поток ввода “не понимает” – ошибка, весь дальнейший ввод будет проигнорирован

2.4.  Общее для потоков ввода и вывода. Состояние потока

Так как наследуются от одного базового класса –ios,

Format flags in an object of type fmtflags An exception mask in an object of type iostate A field width in an object of type int A display precision in an object of type int A locale object in an object of type locale

каждый поток (istream и ostream) в каждый момент времени (после выполнения каждой операции ввода/вывода) находится в определенном состоянии. Установкой и соответствующей проверкой этого состояния вылавливаются ошибки и нестандартные условия. Страуструп 683.

В базовом классе

bool good() const;

следующая операция может выполниться, так как предыдущие успешно выполнились. Иначе операция гарантированно не выполнится.

bool fail() const;

The member function returns true if rdstate() & failbit

следующая операция не выполниться

bool eof() const;

виден конец файла (не 0)

bool bad() const;

поток испорчен. Отличия от fail() незначительны в худшую сторону – здесь Вы вообще не можете быть ни в чем уверены.

iostate rdstate() const;

получение флагов состояния ввода/вывода

void clear(iostate f=goodbit);

сбрасываются флаги ошибок (по умолчанию - все). Обычно после возникновения ошибки нужно сбросить ошибочное состояние, чтобы дальше пользоваться потоком, но этого недостаточно – для восстановления работоспособности еще нужно вручную очистить буфер ввода/вывода.

void setstate(iostate f){clear(rdstate() | f);}

добавление f к флагам состояния

operator void*() const;

не ноль, если! fail()

bool operator!() const {return fail();}

не good()

Пример: проще всего состояние потока можно проверить как обычное логическое выражение. Обычно хочется проверить – пользователь ввел то, что ожидает программа, или «пошутил».

{

double d;

cin>>d; //1) 2 – преобразуется к d=2.0
2) 2A – d=2.0 – значение сформировано, но «А» еще осталось в буфере потока и ждет приема char
3) 3,3 вместо 3.3 - d=3.0, но запятая и вторая 3 осталась в буфере ввода и ждет ввода
4) вводим AAA - поток испорчен вырабатывается флаг ошибки

if( !cin ) //сюда попадем, если только поток ввода Ваш ввод никаким образом проинтерпретировать не может – 4)

{//пользоваться d нельзя! Значение d не изменилось!!!

//Весь последующий ввод (cin>>) будет проигнорирован!

//Для того чтобы программу можно было выполнять дальше,

//1) сбросить ошибки

cin. clear();//иначе весь последующий ввод будет проигнорирован

}else {используем d}

//2) очистить буфер ввода

cin. ignore(100,'\n');

cin>>d;//теперь можно вводить снова

}

istream& ignore( int nCount = 1, int delim = EOF );

На самом деле все эти функции проверяют флаги. Состояние потока представляется набором флагов (а соответствующие константы для проверки флагов заданы в базовом для ios классе – ios_base):

static const iostate badbit, //поток испорчен

eofbit, //конец файла

failbit, //следующая операция не выполнится

goodbit; //– все хорошо

Флагами состояния можно манипулировать непосредственно:

{

double d;

cin>>d; //вводим QWERTY

if( !cin )

{//пользоваться d нельзя!

//Можно выяснить причину

ios::iostate state; //переменная нужного типа

state = cin. rdstate();

if(state & ios::failbit) cout<<"Ввели чучу, но дальше работать можно!"<<endl; //значение d не изменилось!

if(state & ios::badbit) cout<<"Все пропало!"<<endl;

//сбросить ошибки, чтобы можно было выполнять дальше

}else {используем d}

}

Замечание 1: аналогичным образом можно проверить и ошибку вывода для потока cout, хотя это обычно не делается.

Замечание 2: состояние потока ввода eofbit (конец файла) при вводе не трактуется, как ошибка и поэтому не может быть проверено таким способом. Для отслеживания состояния конца файла (потока) можно применить функцию eof( ), которая возвращает не нуль, если конец файла достигнут:

Обычно: fin - объект для файлового ввода – считываем строки

char ar[N];

int i=0;

while( !fin. eof() )

{

fin. get( szBuf[i++]);//из файла считывает пока не встретится конец файла

}

2.5.  Форматированный ввод/вывод.

До сих пор во всех примерах при вводе/выводе использовались форматы, заданные по умолчанию.

Программисту предоставляется возможность форматировать данные (также как это делала printf()). Каждый поток ввода/вывода связан с набором флагов формата. Эти флаги представляют битовые маски. Эти маски объявлены в классе ios как константы типа fmtflags (enum).

Два способа форматирования: Масками можно пользоваться непосредственно (параметры resetiosflags( long ) и setiosflags) и

2.5.1.  Флаги ввода/вывода и методы для работы с ними

1) Функции для работы с отдельными флагами (не затрагивая остальные)

Основные функции для работы с флагами:

long setf( long lFlags );//добавляет указанные флаги к существующим

long unsetf( long lFlags );//обнуляет (сбрасывает) указанные флаги

long setf( long lFlags, long lMask );//добавляет указанные первым аргументом флаги. Была введена, так как некоторые понятия определяются не одним битом, а несколькими, например, за представление целых чисел отвечают три разных бита.

Поэтому для этой функции в качестве второго параметра используются следующие константы, являющиеся совокупностью флагов:

adjustfield, internal | left | right

basefield, dec | hex | oct //таким образом выделяются только указанные биты

floatfield, fixed | scientific

, fixed, , scientific, showbase, showpoint, showpos, unitbuf, uppercase, adjustfield, , floatfield

Флаг

Назначение

По умолчанию

skipws

если установлен - начальные невидимые символы отбрасываются

установлен

dec, oct, hex

ввод/вывод целых в указанной системе счисления

dec

left, right

выравнивание вывода по левому/правому краю, если задана ширина поля вывода

right

internal

отступ между знаком и значением (-10)

showbase

показывает префиксы для целых в формате oct (0), hex (0x)

нет

uppercase

выводит этот префикс заглавными или строчными буквами

строчными

boolalpha

булевы переменные вводятся/ выводятся true, false

нет

Примеры:

int n=15;

cout. unsetf(ios::dec); //требуется не для всех компиляторов

cout. setf(ios::hex | ios::showbase); //0xF

cout<<n<<endl;

или более общий вариант

cout. setf(ios::hex, ios_base::basefield );

cout. setf(ios::showbase | ios::uppercase );

cout<<n<<endl;//0XF

bool b=true;

cout. setf(ios::boolalpha);

cout<<b<<endl; //выводит «true»

stop

cin. setf(ios::boolalpha);

cin>>b; //Вы печатаете false или true - вводит 0 или 1

2) функции для работы со всеми флагами

если есть необходимость «прочитать» все текущие флаги или установить все сразу –

long flags( long lFlags ); //устанавливает новые, возвращает старые

long flags() const; //возвращает текущие

Пример:

ios::fmtflags f = ios::hex | ios::showbase | ios::uppercase;

cout. flags(f);

cout<<255<<endl;

3) функции width(), precision(), fill()

width()

для вывода задает ширину поля (количество позиций). После вывода возвращается к значению по умолчанию

По умолчанию при выводе любого значения оно занимает столько позиций, сколько символов выводится

precision()

плавающие при выводе округляются до указанного значения. Если формат - scientific или fixed, то количество цифр после запятой, если по умолчанию, то общее количество цифр.

по умолчанию 6 цифр

fill()

установка нового символа для заполнения

по умолчанию - пробел

//width()

cout.width(10);

cout<<"FF"<<endl; //по умолчанию справа

cout.width(10);

cout. setf(ios::internal, ios::adjustfield);

cout<<-2<<endl;

cout.width(10);

cout. setf(ios::left, ios::adjustfield);

cout<<"BB"<<endl; //слева

cin. width(4);

cin>>ar[i]; //сколько бы не вводили – в массив запишет 3 байта+0, но все остальное останется в буфере ввода и будет принято в следующую строчку массива!

// precision

cout.precision(3);

cout<<1.23456; //будет выведено 1.23

// fill

cout. width(10);

cout. setf(ios::internal, ios::adjustfield);

cout. fill('#');

cout<<-2<<endl; // -########2

2.5.2.  Манипуляторы ввода/вывода

Другое средство форматирования – манипуляторы ввода/вывода – для того, чтобы избавить программиста от необходимости изменять состояние потока посредством флагов, стандартная библиотека предоставляет набор специальных функций – манипуляторов. Ключевая идея – вставлять между объектами вызов функции, но в удобном виде (если операции записываются как отдельные инструкции, логические связи между ними не очевидны): Страуструп 698

cout<<flush; //перегруженный оператор <<, который принимает в качестве аргумента указатель на функцию и вызывает ее.

это означает: cout. operator<<(flush); -> flush(cout) -> cout. flush();

cout<< hex<<255<<endl; //передается адрес функции

ios_base& hex(ios_base& str);

The manipulator effectively calls str. setf(ios_base::hex, ios_base::basefield), then returns str.

Замечание: для обращения к некоторым из этих функций (манипуляторам с параметрами)- #include <iomanip>

Шилдт 255

В таблице приведены основные манипуляторы (Замечание: имена многих манипуляторов совпадают с именами флагов и функций.)

Имя

Действие

Используется

dec

Устанавливает десятичную систему счисления (используется по умолчанию)

для ввода-вывода

hex

Устанавливает шестнадцатеричную систему счисления

для ввода-вывода

oct

Устанавливает восьмеричную систему счисления

для ввода-вывода

ws

??Ввод пробельных символов (по умолчанию они пропускаются)

только для ввода

endl

Вставляет символ новой строки и очищает поток вывода

только для вывода

flush

Очищает поток вывода

только для вывода

ends

Добавляет нулевой байт

только для ostrstream

setbase( int )

Устанавливает систему счисления в 0, 8, 10 или 16

для ввода-вывода целых : по умолчанию - 0 (десятичная система)

resetiosflags( long )

Очищает биты формата во вводном и выводном форматах числом, заданным аргументом

для ввода-вывода

setiosflags( long )

Устанавливает биты формата во вводном и выводном потоках в соответствии с аргументом

для ввода-вывода

setfill( int )

Устанавливает символ заполнитель (по умолчанию таким символом является пробел)

для вывода

setprecision( int )

Устанавливает точность для типа с плавающей точкой (по умолчанию точность 6)

для вывода

setw( int )

Устанавливает ширину поля

для ввода-вывода

ends

Вставляет завершающий нулевой символ строки

только для ostrstream

Замечание: при использовании манипуляторов без параметров – не ставьте скобки, при использовании манипуляторов с параметрами – не забудьте подключить <iomanip>

Пример:

double d = 1.234567;

cout<<setprecision(4)<<d; //1.цифры с округлением. Количество цифр остается 4 до следующего setprecision

cout<<setw(10)<<setfill('#')<<d<<endl;//#####1.235

????cin>>noskipws>>x; //не пропускать символы-разделители????

С помощью манипуляторов resetiosflags( long ) и setiosflags( long ) можно установить или сбросить флаги (биты формата следующим образом:

cout<<setw(10)<<setiosflags(ios::left | ios::adjustfield)<<"AAA"<<endl;

Замечание: манипуляторы, определяемые пользователем. Страуструп стр 701. Шилдт 273

ostream& mymanip(ostream& os)

{

os. width(10);

os. fill(‘#’);

os. precision(4);

return os;

}

void main()

{

cout<< mymanip<<1.23456<<endl;

}

2.6.  Файловый ввод/вывод

1)  Для получения сервисов файлового ввода/вывода следует подключить <fstream>. Так как классы ifstream, ofstream являются производными от istream, ostream, а те в свою очередь производными от ios – все базовые операции с потоками являются общими.

#include <fstream>

2)  сервисы стандартной библиотеки по-прежнему находятся в пространстве имен std

3)  Отличие: если стандартные объекты cin, cout… предоставляются Вам по умолчанию, то объекты для файлового ввода/вывода требуется создавать «вручную». Две возможности связать такой объект с файлом:

а) классы предоставляют соответствующий конструктор:

ifstream( const char* szName, int nMode = ios::in, int nProt = filebuf::openprot );//один из конструкторов – по умолчанию открывается для ввода в текстовом режиме. Файл может быть sharing (разделяемым)

ifstream iff(“My. txt”);//если файл существует, он открывается для чтения, если нет – создается и открывается для чтения

ifstream iff(“My. txt”);, ios::nocreate | ios::in);//если существует такой файл, открывается, если нет – функция не выполняется

ifstream iff(“My. txt”, ios::binary | ios::in, filebuf::sh_none);//файл открыт для чтения в двоичном режиме, совместный доступ к файлу запрещен

б)создать объект по умолчанию и связать его с файлом с помощью метода open()

void open(const char* szName, int nMode = ios::in, int nProt = filebuf::openprot);

ifstream iff();

iff. open(“My. txt”);

4)  Проверка корректности создания и открытия файла:

if(!iff){cout<<”Failed!”;…return;}

5)  В зависимости от того, в каком виде представлены данные, для работы с объектом iff, Вы пользуетесь соответствующими функциями

6)  после использования обязаны файл закрыть:

iff. close();

2.6.1.  Произвольный доступ

Система воода/вывода С++ управляет двумя указателями, связанными с файлом:
указатель считывания (get pointer), который задает позицию, начиная с которой произойдет следующее считывание (ввод)
указатель записи (put pointer), который задает позицию в файле, с которой начнется следующая запись.

При каждом вводе и выводе соответствующий указатель перемещается по результатам этой операции. Две функции, которые позволяют «непоследовательно» работать с файлом:

istream& seekg( streampos pos );//задает новую текущую позицию (streampos==long)

istream& seekg( streamoff off, ios::seek_dir dir );//off - смещение от того, что задано вторым параметром (streamoff==long)
откуда считать смещение: ios::beg – от начала
ios::cur – от текущего
ios::end – от конца

Изменяет get pointer

ostream& seekp( streampos pos );

ostream& seekp( streamoff off, ios::seek_dir dir );

Изменяет put pointer

Определить текущую позицию каждого из указателей можно с помощью:

pos_type tellg();

pos_type tellp();

2.7.  Неформатированный ввод/вывод

Применяется в основном для файлового ввода/вывода, хотя в приведенных примерах мы пользовались методом get() просто для считывания последовательности байтов из cin. Форматированный ввод/вывод хорошо, но часто требуется хранение данных в двоичном виде. То есть человек вряд ли сумеет прочитать такой файл, а для Вашей программы данные хранятся в более компактном виде.

2.7.1.  Основные методы: - get() и put().

Перегрузка

Описание

int get();

Извлекает один байт из потока и возвращает его значение

get( char* buf, int nCount, char delimeter);

Извлекает байты из потока пока не встретит байт (символ)- разделитель (delimeter) или пока не извлечет а) nCount байт, б) встретит конец файла. Извлеченные байты помещаются в buf + добавляется 0-ой байт. Замечание: если строка оказалась длиннее nCount, то введено будет nCount-1 + 0

get( char& );

Извлекает один байт из потока и помещает в указанный байт.

get( streambuf&, char );

Gets characters from the stream and stores them in a streambuf object until the delimiter is found or the end of the file is reached. The ios::failbit flag is set if the streambuf output operation fails.

Замечание: во всех случаях сам delimeter не извлекается из потока и не записывается в указанный буфер!!!

Пример:

{

char ar[3][4];//={0};

for(int i=0; i<3; i++)

{

cin. get(ar[i],4,'\n');//считывает, пока не встретится указанный символ-разделитель или пока не будет считано 4 элементов

//cin. get();если символов больше - останутся в буфере и введутся в

//следующую строчку массива

while(cin. get()!='\n')

;//тогда “дочитываем” - извлекаем из потока, но никуда не записываем

}

2.7.2.  GetLine()

Главное отличие: функция извлекает из потока delimeter, но не записывает в указанный буфер.

istream& getline( char* pch, int nCount, char delim = '\n' );

Извлекает байты из потока, пока не встретит delimeter или не считает nCount–1 байт в указанный массив + дополнит 0-ым байтом. Если встретит delimeter, извлечет его из потока, но не запишет в массив.

char ar[3][4];//={0};

for(int i=0; i<3; i++)

{

cin. getline(ar[i],4,'\n');//если вводим 3 и меньше, то все OK - AAA, BB, C

}

Узнать, сколько действительно было считано байт, можно с помощью gcount()

int gcount() const;

2.7.3.  read() write() gcount()

istream& read( char* pch, int nCount );

Извлекает из потока nCount байт или пока не достигнут конец файла. Узнать, сколько действительно было считано байт, можно с помощью gcount()

{

ifstream iff(“My. dat”, ios::in | ios::binary);

if(!iff){…}

else

{

double d;

iff. read( reinterpret_cast<char*>(&d), sizeof(double) );

iff. close();

}

}

2.8.  Строковый ввод/вывод


В манипуляторах resetiosflags( long ) и setiosflags( long ) биты формата кодируются следующим образом:

class ios

{

public:

enum

{

skipws = 0x0001, // Пропускать пробелы при вводе

left = 0x0002, // Прижимать при выводе к левой

// границе поля

// Прижимать при выводе к правой границе поля

right = 0x0004,

internal = 0x0008, // При выводе центрировать в поле

dec = 0x0010, // Десятичная система счисления

oct = 0x0020, // Восьмеричная система счисления

hex = 0x0040, // Шестнадцатеричная система

// счисления

showbase = 0x0080, // Показать базу счисления

showpoint = 0x0100, // При выводе отображать

// десятичную точку

uppercase = 0x0200, // Печатать шестнадцатеричными

// прописными цифрами

showpos = 0x0400, // Печатать "+" перед

// положительным числом

scientific

= 0x0800, // Печатать в виде 1.5E-3

fixed = 0x1000, // Печатать в виде 1.504

unitbuf = 0x2000, // Выгрузить все потоки после

// ввода

stdio = 0x4000, // Выгрузить все потоки после

// вывода

};

// ...

};

В записи аргументов этих функций биты форматов можно комбинировать, используя побитовую операцию ИЛИ (|), например:

ios :: left | ios :: fixed

Пример:

#include <iostream> // Для потокового ввода-вывода

#include <iomanip> // Для параметризованных

// манипуляторов

//*****

// Тестирование

int main( void ) // Возвращает 0 при успехе

{

double dbls[ ] = {

1.245, -12.99133, 134. -2.345, 0.000003

};

cout << setfill( '.' ) << setprecision( 4 )

<< setiosflags( ios::showpoint | ios::fixed

| ios::right );

for( int i = 0;

i < sizeof( dbls )/sizeof( dbls[ 0 ] ); i++ )

{

cout << " Outcome " << setw( 20 ) << dbls[ i ]

<< endl;

}

return 0;

}

Результаты выполнения программы имеют следующий вид:

Outcome..............1.2450

Outcome............-12.9913

Outcome............134.0078

Outcome.............-2.3450

Outcome..............0.0000

2.8.1.  Методы класса ostream

Замечание: 1) члены ostream не виртуальны 2) inline. Причина – обеспечить максимальное быстродействие (избежать расходов просто на вызов - inline и на косвенный вызов функций посредством таблиц виртуальных функций) (Страуструп 679).

3.  Форматируемый ввод/вывод

То, что разработчик прикладных программ считает выводом, на самом деле является преобразованием объектов некоторого типа (int, char*, MyString) в последовательность символов (строковое представление).

До сих пор в примерах использовались форматы, заданные в С++ по умолчанию. Однако программисту предоставляется также возможность форматировать данные (также как это делала printf()).

Каждый поток ввода/вывода связан набор флагов формата (format flags), которые управляют способом форматирования информации и представляют собой битовые маски (bitmasks). Эти маски объявлены в классе ios как enum типа fmtflags.

3.1.  Потоки вывода

Класс ostream (wostream)– преобразование значений разного типа в последовательность символов и вывод по умолчанию на экран (специализации шаблона basic_ostream – Страуструп 675).

The clear() member function clears the fail bit. However, the istream object is still unusable. The sample code below clears the fail bit and extracts the unusable characters left in the streambuf object.

Sample Code

/* No special compile options needed. */

#include <iostream. h>

int ClearError(istream& isIn) // Clears istream object

{

streambuf* sbpThis;

char szTempBuf[20];

int nCount, nRet = isIn. rdstate();

if (nRet) // Any errors?

{

isIn. clear(); // Clear error flags

sbpThis = isIn. rdbuf(); // Get streambuf pointer

nCount = sbpThis->in_avail(); // Number of characters in buffer

while (nCount) // Extract them to szTempBuf

{

if (nCount > 20)

{

sbpThis->sgetn(szTempBuf, 20);

nCount -= 20;

}

else

{

sbpThis->sgetn(szTempBuf, nCount);

nCount = 0;

}

}

}

return nRet;

}