Манипуляторы потоков, задающие формат вывода вещественного числа



      Число печатаемых разрядов  справа      от десятичной точки        для вещественного   числа можно     задать с помощью манипулятора потока setprecision или метода precision. Вызов любой из этих установок точности действует для последующих операций вывода до тез пор, пока не будет произведена следующая установка точности.

В классе ios объявлено два перегруженных метода precision.

int ios::precision() – возвращает значение точности представления при выводе вещественных чисел;

int ios::precision(int) – устанавливает значение точности представления при выводе вещественных чисел, возвращает старое значение точности.

Пример. Использование метода precision и манипулятора setprecision для задания точности вывода вещественных чисел.

 

#include <iostream.h> #include <iomanip.h> int main()

{

cout.precision(10); cout<<sqrt(3.0)<<endl; //1.732050808 cout<<cout.precision()<<endl; //10

cout<<setprecision(4)<<sqrt(3.0)<<endl; //1.7321 return 0;

}

 

     Манипуляторы потоков, устанавливающие ширину поля

 

Метод width класса ios и манипулятор setw устанавливают ширину поля. Под шириной поля понимается число символьных позиций, в которые значение будет выведено, или число символов, которые будут выведены. Если обрабатываемые значения имеют меньше символов, чем заданная ширина поля, то для заполнения лишних позиций используются заполняющие символы. Если число символов в обрабатываемом значении больше, чем заданная ширина поля, то лишние символы не отсекаются.

Установка ширины поля применяется только к текущей операции

«поместить в поток» или «взять из потока». После выполнения этих операций ширина поля устанавливается неявным образом на 0. Такая установка означает, что поле для представления выходных данных будет необходимой ширины. Формат манипулятора setw: setw(int). Метод width имеет две реализации:

int ios::width() – возвращает значение ширины поля ввода/вывода;

int ios::width(int) – возвращает значение ширины поля ввода/вывода, возвращает старое значение ширины.

Пример. Использование метода width и манипулятора setw для задания ширины поля.

 

#include <iostream.h> #include <iomanip.h>

cin.width(15);

cin>>str; //012345678901234567890

cout.width(10);

cout<<str; //01234567890123 cout<<endl;

cin.width(5);

cin>>str; //012345678901234567890 или 01

cout<<setw(10)<<str; //xxxxxx0123 или xxxxxxxx01 (x – пробел) return 0;

}

 

Замечание. Для того чтобы обеспечить размещение во входной строке нулевого символа, считывается на один символ меньше, чем установленная ширина поля.

 

     Манипуляторы, определяющие вид вводимых–выводимых значений

 

ws – извлечение пробельных символов;

endl – вставка символа новой строки и очистка потока; ends – вставка оконечного пустого символа в строку; flush – сброс на диск и очистка ostream;

setfill(int c) – установка символа-заполнителя в c.

 

#include <iostream.h>

#include <iomanip.h> int main()

{

cin.width(5);

cin>>str; //012345678901234567890

cout<<setfill('#')<<setw(10)<<str; //######0123 return 0;

}

 

Работать с символами заполнения можно также с помощью двух перегруженных методов класса ios:

char ios::fill() – возвращает текущий символ заполнения;

char ios::fill(char) – устанавливает значение текущего символа заполнения; возвращает значение старого.

 

 

Создание собственных манипуляторов потока

 

Пользователи могут создавать собственные манипуляторы потокв.

Пример. Создание и использование манипулятора tab. #include <iostream.h>

#include <iomanip.h>

ostream & tab(ostream &output)

{return output<<'\t';}

cout<<tab<<tab<<str<<endl; return 0;}

 

Флаги состояний формата

Различные флаги формата (format flags) задают виды форматирования, которые выполняются во время операций ввода–вывода. В таблице приведены различные флаги формата.

Флаг Описание
ios::skipws При извлечении пробельные символы игнорируются
ios::left Выравнивание по левому краю поля
ios::right Выравнивание по правому краю поля
ios::internal Знак числа выводится по левому краю, число – по правому
ios::dec Десятичная система счисления
ios::oct Восьмеричная система счисления
ios::hex Шестнадцатеричная система счисления
ios::showbase; Выводится основание системы счисления (0x – шестнадцатеричная, 0 – восьмеричная)

 

ios::showpoint

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

ios::uppercase

Предписывает использовать прописные буквы в шестнадцатеричных числах и экспоненциальной форме вещественных чисел.

ios::showpos

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

ios::scientific Определяет вывод экспоненциальной форме вещественных чисел в
ios::fixed

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

ios::showpoint

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

 

Для работы с флагами можно использовать методы класса ios:

long ios :: flags () – возвращает текущие флаги.

long ios :: flags ( long ) – присваивает новые значения флагам и возвращает старые.

long ios::setf(long, long) – перед установкой некоторых флагов позволяет сбросить флаги, которые не могут быть установлены одновременно с ними. В качестве первого параметра передается

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

adjustfield (left | right | internal) basefield (dec | oct | hex) floatfield (scientific | fixed)

long ios::setf(long)  – устанавливает флаги формата, заданные в качестве аргумента и возвращает предыдущие установки этих флагов.

long ios::unsetf(long)  – сбрасывает указанные флаги формата и возвращает предыдущие их значения.

Для работы с флагами можно также воспользоваться манипуляторами с параметрами:

setiosflags(long) – устанавливает флаги формата, указанные в аргументе.

resetiosflags(long) – сбрасывает флаги формата, указанные в аргументе.

Пример. Использование флагов состояния формата

 

#include <iostream.h>

#include <iomanip.h> int main()

{

cout.setf(ios::showpoint); //устанавливаем флаг вывода вещественных чисел в виде числа с десятичной точкой

cout<<9.0000<<endl; //9.00000 cout<<9.9000<<endl; //9.90000 cout<<9.9900<<endl; //9.90000

cout.unsetf(ios::showpoint); //снимаем флаг вывода вещественных чисел в виде числа с десятичной точкой

cout<<9.0000<<endl; //9 cout<<9.9000<<endl; //9.9 cout<<9.9900<<endl; //9.99

cout.setf(ios::hex, ios::basefield); //устанавливаем флаг вывода целого числа в шестнадцатеричном виде

int x=12345; cout<<x; //3039

cout.unsetf(ios::hex); //снимаем флаг вывода целого числа в шестнадцатеричном виде

cout<<endl<<setw(30)<<setiosflags(ios::left)<<x;        //12345 (устанавливаем флаг вывода символов по левому краю поля)

cout<<resetiosflags(ios::left)<<endl; // снимаем флаг вывода символов по левому краю поля

cout.flags(ios:: showpos | ios:: internal); //устанавливаем флаг вывода знака числа и флаг вывода знака числа, прижатого к левому краю, и самого числа, прижатого к правому краю

cout<<setw(10)<<setfill('#')<<x<<endl;//+####12345

cout.flags(ios::left); //          устанавливаем флаг  вывода                         символов       по левому краю поля

cout<<setw(10)<<setfill('%')<<x<<endl; //+12345%%%% cout.setf(ios::showbase); //устанавливаем флаг специфического

отображения шестнадцатеричных и восьмеричных чисел cout<<oct<<x<<endl; //030071 cout<<hex<<x<<endl; //0x3039 cout<<dec<<x<<endl; //+12345

double y=9000, z=0.0009;

cout.unsetf(ios::showpos); // снимаем флаг вывода знака числа cout.setf(ios::scientific | ios::uppercase); //устанавливаем флаг вывода

вещественных чисел в экспоненциальной форме и флаг вывода прописных в представлении чисел

cout<<y<<" "<<z<<endl; //9.00000E+003 9.000000E-004

cout.unsetf(ios::uppercase); //снимаем флаг вывода прописных в представлении чисел

cout<<y<<" "<<z<<endl; //9.00000e+003 9.000000e-004

cout.setf(ios::fixed, ios::floatfield); //устанавливаем флаг вывода вещественных чисел в виде числа с десятичной точкой

cout<<y<<" "<<z<<endl; //9000.000000 0.000900

cout.setf(ios::hex | ios::uppercase); ///устанавливаем флаг вывода целого числа в шестнадцатеричном виде и флаг вывода прописных в представлении чисел

cout<<31<<endl; //0X1F return 0;

}

 

СОСТОЯНИЕ ОШИБОК ПОТОКА

 

Состояние ошибок потока можно проверить с помощью битов класса ios. Совокупность этих битов определена в поле state класса ios.

enum io_state { goodbit = 0x00,

eofbit = 0x01, failbit = 0x02, badbit = 0x04 };

Состоянием потока можно управлять с помощью методов и операций.

Бит eofbit автоматически устанавливается, когда встречается признак конца файла. Для проверки состояния этого бита можно использовать метод int ios::eof(). Вызов cin.eof(); возвращает true, если встретился признак конца файла, и false – в противном случае.

Бит failbit устанавливается для потока, если в потоке происходит ошибка форматирования, но символы не утеряны. Проверить состояние этого бита можно с помощью метода int ios :: fail (), который возвращает ненулевое значение, если бит failbit установлен.

Бит badbit устанавливается для потока при возникновении ошибки, которая приводит к потере данных. Проверить состоянии этого бита можно с помощью методов int ios::fail() и int ios::fail() класса ios. Если бит badbit установлен, эти функции возвращают ненулевое значение.

Бит goodbit устанавливается, если нет ошибок в потоке. Состояние этого бита проверяет функция int ios::good(). В случае отсутствия ошибок эта функция возвращает истину.

Метод int ios::rdstate() возвращает текущее состояние потока. Вызов cout.rdstate(), например, вернул бы состояние потока, которое затем могло бы использоваться в операторе switch, который бы проверял состояние битов ошибок потока.

Пример использования метода rdstate():

int k=cin.rdstate();

if(k & ios::eofbit) cout<<"Достигнут конец файла"<<endl;

Метод int ios::clear(int = 0) можно использовать для установления состояния ошибки. Если вызвать этот метод без параметров (вызов по умолчанию), то поток устанавливается в нормальное состояние, при котором можно продолжать выполнять операции ввода-вывода данного потока. Вызов без параметров:

cin.clear();

Установка бита failbit:

cin.clear(failbit);

Подобный вызов может использоваться, если возникают проблемы при обработке cin с типом, определенным пользователем.

Метод ios::operator!()   возвращает ненулевое значение, если установлен хотя бы один бит ошибки.

Метод  ios::operator void*() возвращает ненулевой указатель, если установлен хотя бы один бит ошибки.

Пример. Проверка состояний ошибок.

 

#include <iostream.h>

int main()

{

int x;

cout<<"До ошибочной операции ввода:"<<endl; cout<<"cin.rdstate(): "<<cin.rdstate()<<endl; //0 cout<<"cin.eof(): "<<cin.eof()<<endl; //0 cout<<"cin.fail(): "<<cin.fail()<<endl; //0 cout<<"cin.bad(): "<<cin.bad()<<endl; //0 cout<<"cin.good(): "<<cin.good()<<endl; //1 cin>>x; //вводится символ

cout<<"После ошибочной операции ввода:"<<endl; cout<<"cin.rdstate(): "<<cin.rdstate()<<endl; //2

cout<<"cin.eof(): "<<cin.eof()<<endl; //0 cout<<"cin.fail(): "<<cin.fail()<<endl; //2 cout<<"cin.bad(): "<<cin.bad()<<endl; //0 cout<<"cin.good(): "<<cin.good()<<endl; //0 cout<<!cin<<endl; //2

cin.clear();

cout<<"После cin.clear():" <<endl; cout<<"cin::fail(): "<<cin.fail()<<endl; //0 cout<<"cin.good(): "<<cin.good()<<endl; //1 cout<<!cin<<endl; //0

return 0;

}

 

Связывание выходного и входного потоков

Интерактивные приложения обычно включают класс istream для ввода и класс ostream для вывода. Очевидно, что в таких приложениях приглsd,uiашение на ввод должно появляться до осуществления операции ввода. В языке C++ есть метод tie, который выполняет синхронизацию (связывание) выполнения операций над потоками istream и ostream. Этот метод гарантирует, что вывод появится раньше последующего ввода. В C++ происходит автоматическое связывание объектов cin и соut:

cin.tie(&cout);

При программировании следует связывать другие пары потоков классов istream и ostream.

Например, для того чтобы развязать входной поток InputStream от выходного:

InputStream.tie(0);

 

Файлы и потоки

В C++ каждый файл рассматривается как последовательность байтов. Каждый файл завершается маркером конца файла (end-of-file marker). Когда файл открывается, то создается объект и с этим объектом связывается поток. Для обработки файлов в C++ должны быть включены в программу заголовочный файлы <iostream.h> и <fstream.h>. Файл <fstream.h> включаеи определения классов потоков ifstream (для ввода из файла), ofstream (для вывода в файл) и fstream (для ввода-вывода файлов). Файлы открываются путем создания объектов этих классов потоков. Так эти классы потоков являются производными от классов istream, ostream и iostream, то они могут использовать методы, операции и манипуляторы, определенные в их базовых классах.

 

Создание файла последовательного доступа

Так как C++ не предписывает файлу никакой структуры, то программист должен задавать структуру файлов в соответствии с требованиями прикладных программ.

Пример. Занесение данных о студенте, его группе и среднем балле в текстовый файл.

#include <iostream.h> #include <fstream.h> int main()

{

/*Так как файл открывается для ввода, то создается объект класса ofstream. Конструктору этого класса передается два параметра – имя файла и режим открытия файла.*/

ofstream outGroupFile("student.dat",ios::out);

/*Для проверки того, успешно ли открылся файл, используется перегруженный метод opearator! класса ios. Если файл не открыт, он возвращает ненулевое значение.*/

if(!outGroupFile)

{

cerr<<"File not open"<<endl; return 0;

}

char name[30],group[10]; double AverMark; cout<<"?: ";

while(cin>>name>>group>>AverMark)

{ /*Условие в заголовке оператора while автоматически вызывает перегруженный метод operator void* класса ios. Эта функция превращает поток в указатель, который можно проверить на равенство 0. Ввод признака конца файла (Ctrl+Z) установит бит failbit для cin, после проверки которого метод operator void* вернет 0, и условие цикла while станет ложным. Таким образом, метод operator void* можно использовать для проверки конца файла в объекте ввода вместо явного вызова метода eof.*/

outGroupFile<<name<<' ' <<group<<' '<<AverMark<<'\n';

/* информация записывается в файл «student.dat» с помощью объекта outGroupFile, связанного с этим файлом, и операции «поместить в поток» <<.*/

cout<<"?: ";

}

OutGroupFile . close ();

/*метод close() осуществляет явный вызов деструктора объекта outGroupFile, закрывающего файл.

return 0;

Таблица. Режимы открытия файлов

Режим Описание
ios::app Записать данные в конец файла без модификации имеющихся данных в файле.
ios::ate Переместиться в конец исходного открытого файла. Данные могут быть записаны в любое место файла.
ios::in Открыть файл для ввода.
ios::out Открыть файл для вывода. Если в файле есть данные, то они уничтожаются. Если файла не существует, он создается.
ios::trunc Уничтожать содержимое файла, если он существует.
ios::binary Открыть файл для двоичного ввода или вывода.

 

Таблица. Соответствие между режимами открытия файла класса ios и режимами открытия файла, описанными в <stdio.h>

Комбинация флагов ios

Эквивалент stdio

binary in out trunc app
    +     “w”
    +   + “a”
    + +   “w”
  +       “r”
  + +     “r+”
  + + +   “w+”
+   +     “wb”
+   +   + “ab”
+   + +   “wb”
+ +       “rb”
+ + +     “r+b”
+ + + +   “w+b”

 

Замечание. Кроме как с помощью конструктора, открыть файл в программе можно с помощью метода open, имеющего такие же параметры как и конструктор. Например,

ofstream outGroupFile; outGroupFile.open("student.dat",ios::out);

Пример. Чтение данных из файла последовательного доступа и вывод их на экран.

#include <iostream.h> #include <fstream.h> #include <iomanip.h>

void OutputLine(const char* name, const char *group, double mark)

{

cout<<setiosflags(ios::left)<<setw(20)<<name

<<setw(10)<<group<<setw(8)<<setprecision(2)

<<resetiosflags(ios::left)<<mark<<'\n';

Int main()

{

Ifstream inGroupFile;

/* Как и класс ofstream класс ifstream имеет конструктор с двумя аргументами – именем файла и режимом его открытия. Если режим открытия файла не указан, то значением по умолчанию является ios::in. Таким образом, можно создать объект класса ifstream и передать ему один параметр – имя файла. Например,

ifstream inGroupFile("student.dat");

Для открытия файла на чтение можно также воспользоваться созданием объекта класса ifstream с помощью конструктора без параметров с последующим вызовом для него метода open*/

inGroupFile.open("student.dat",ios::in); if(!inGroupFile)

{/*К объекту класса ifstream, как и к объекту класса ofstream, можно применить перегруженный метод operator! для того, чтобы проверить, успешно ли открылся файл*/

cerr<<"File not open"<<endl; return 0;

}

char name[30],group[10]; double AverMark;

cout<<setiosflags(ios::left)<<setw(20)<<"Name of student"

<<setw(10)<<"Group"<<"Av. mark\n"<< setiosflags(ios::fixed|ios::showpoint); while(inGroupFile>>name>>group>>AverMark)

/*В условии цикла while используется перегруженный метод operator void*() для чтения данных из файла. Этот метод возвращает 0, если будет достигнут конец файла.*/

OutputLine(name,group,AverMark); inGroupFile.close();

Return 0;

}


Дата добавления: 2019-09-13; просмотров: 267; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!