КаталогИндекс раздела
НазадОглавлениеВперед


Лабораторная работа ╧5.
Использование библиотеки ввода-вывода языка С++

1. Цель работы

Целью лабораторной работы является получение практических навыков при использовании флагов и манипуляторов из библиотеки ввода.вывода языка С++.

Краткое теоретическое введение.
Потоки языка С++

Система ввода.вывода С++ , так же как и в языке С, оперирует потоками (streams). В начале выполнения программы автоматически открывается 4 предоставленных потока: cin, cout, cerr и clog. Поток cin связан со стандартным вводом, поток cout - со стандартным выводом. Поток cerr небуферизированный , т.е. вызывает немедленный вывод. Поток clog буферизирован, и вывод происходит только после того, как наполнится буфер. Оба эти потока используются для вывода сообщений об ошибках.

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

В заголовочном файле IOSTREAM.H определены классы, относящиеся потокам.Эти классы образуют иерархическую систему.

Класс нижнего уровня называют streambuf. Он обеспечивает основные операции по неформатированному выводу. Следующий класс называется ios. Он обеспечивает поддержку форматированного ввода/вывода и используется для построения трёх следующих классов: istream, ostream и iostream. istream позволяет создать поток ввода, ostream - поток вывода. Класс iostream может создавать поток, как для ввода, так и для вывода.

Перегрузка операций ввода/вывода. Инсерторы и экстракторы

Операция << вставки данных в поток (inserting) , будем называть экстрактором(extractor)

В качестве примера создания функции инсертора рассмотрим класс vector:


			class vector{
			public:
			  int x, y, z;
			  vector (int a,int b,int c){x=a; y=b; z=c;}
			}; 

Перегрузка операции << для этого класса осуществляется


			ostream &operator <<(ostream &stream, vector obj)
			{
			  stream << obj.x << ", ";
			  stream << obj.y << ", ";
			  stream << obj.z << "\n";
			  return stream;
			};

Ну и блок main для демонстрации работы класса


			#include <iostream.h>
			class vector{
			public:
			  int x, y, z;
			  vector (int a,int b,int c){x=a; y=b; z=c;}
			};
			ostream &operator <<(ostream &stream, vector obj)
			{
			  stream << obj.x << ", ";
			  stream << obj.y << ", ";
			  stream << obj.z << "\n";
			  return stream;
			};
			main(void)
			{
			  vector a(1,2,3),b(3,4,5);
			  cout << a << "\n" << b << "\n";
			  return 0;
			}

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

		ostream &operator <<(ostream &stream,class_type obj)
		 {
		   //тело программы
		  return stream;
		 }

Выше мы использовали вариант stream<

Перегрузка операции >> для класса vector осуществляется

			istream &operator >> (istream &stream,vector &obj)
			{
			  cout << "Enter x,y,z:";
			  stream >> obj.x >> obj.y >> obj.z;
			  return stream;
			}

Пример общей работы

			#include <iostream.h>
			class vector{
			public:
			  int x, y, z;
			  vector (int a,int b,int c){x=a; y=b; z=c;}
			friend ostream& operator << (ostream &stream,vector obj);
			friend istream& operator >> (istream &stream, vector &obj);
			};
			ostream &operator <<(ostream &stream, vector obj)
			{
			  stream << obj.x << ", ";
			  stream << obj.y << ", ";
			  stream << obj.z << "\n";
			  return stream;
			};
			istream &operator >> (istream &stream,vector &obj)
			{
			  cout << "Enter x,y,z:";
			  stream >> obj.x >> obj.y >> obj.z;
			  return stream;
			}
			main(void)
			{
			  vector a(1,2,3);
			  cout << a;
			  cin >> a;
			  cout << a;
			  return 0;
			}

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

Для того чтобы организовать форматированый ввод и вывод , анологичный тому , что предостаыляют пользователю функции printf() и scanf() в языке C++ используются два способа.

Первый состоит в применении функций членов - класса ios.

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

Флаги (Использование функций-членов класса ios)

Состояние правил форматного вывода в поток определяется состоянием флагов форматированого потока. В заголовочном файле iostream.h определено следущее перечисление , задающее флаги форматирования:

enum    {
        skipws    = 0x0001, // отбрасывание пробелов
        left      = 0x0002, // выравнивание по левому краю
        right     = 0x0004, // выравнивание по правому краю
        internal  = 0x0008, // заполнение пустых позиций
        dec   = 0x0010,     // выдача в десятеричном формате
        oct   = 0x0020,     // выдача в восьмеричном формате
        hex   = 0x0040,     // выдача в шестнадцетиричном формате
        showbase  = 0x0080, // выдача основания системы счичления
        showpoint = 0x0100, // выдача позиции точки
        uppercase = 0x0200, // выдача в формате xx.xxxx Exx
        showpos   = 0x0400, // выдача знака у положительного числа
        scientific= 0x0800, // выдача в форме с фиксированной точкой
        fixed     = 0x1000, // выдача в форме с плавающей точкой
        unitbuf   = 0x2000, // улучшенная выдача
        stdio     = 0x4000  // щсвобождение потока
};

* Формат соответствует целому тиа long. Изменить состояние флагов можно функцией

long setf(long flags)
.

* Чтобы установить флаг showbase в режим включено (on), используем оператор

stream.set(ios::showbase);

здесь stream - тот конкретный поток , на который мы воздействуем.

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

cout.setf(ios::left | ios::hex);

* Функция

unsetf(long flagsl)
возвращает флаг в состояние выключено(off).

* Функция

long flags(void)
возвращает текущее состояние флагов

* Функция

int width(int len)
Возвращает текущую ширину поля выдачи и устанавливает её ширину len.

* Функция

char fill(char ch)
возвращает текущий символзаполнения устанавливает новый символ ch заполнения.

* Функция

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

Использование этого способа иллюстрирует следующий пример:

#include <iostream.h>
#include <iomanip.h>
main(void)
{
  long fl;
  fl= cout.flags();
  cout << "Исходное состояние флагов: "<< fl<<"\n";
  
  cout.setf(ios::showpos);
  cout.setf(ios::scientific);
  cout << 123 << " " << 1.2345678 <<"\n";

  cout.setf(ios::hex | ios::showbase);
  cout.unsetf(ios::showpos);
  cout.width(20);
  cout.precision(10);
  cout << 123 << " " << 123.456 << " " << 1.2345678 << "\n";
  cout << "Новое состояние флагов: " << cout.flags() << "\n";
  cout.flags(fl);
  cout << "После востановления исходного состояния флагов: \n";
  cout << 123 << " " << 123.456 << 1.2345678 << "\n";
  return 0;
}

Использование манипуляторов

Для управления форматом выдачи из потока можно использовать специальные функции, называемые манипуляторами. Стандартными манипуляторами, доступ к которым можно получить , подключив файл iomanip.h , являются:

Манипулятор		Действие манипулятора
_________________________________________________________________
dec			Десятичный формат
endl			Вывод символа '\n' и освобождение буфера
ends			Вывод NULL
flush			Освободить поток
hex			Шестнадцатеричный формат числа
resetioflags(long f)	Отключить флаги , определённые f
setbase(int base)	Установить основание системы счисления
setfill(char ch)	Установить символ заполнения
setiosflags(long f)	Установить режим on флагам , указанным f
setprecision(int p)	Установить число цифр после десятичной точки
setw(int w)		Установить ширину поля выдачи
ws			Режим пропуска символов пробела
_________________________________________________________________

Использовать стандартных манипуляторов можно продемонстрировать следующим примером:

#include <iostream.h>
 #include <iomanip.h>
main(void)
{
  cout << setprecision(2) << 100.5375 << endl;
  cout << setw(20) << "MANIPULATORS \n";
  return 0;
}

Создание манипуляторов

Можно создать свою собственную функцию - манипулятор. Покажем, как сделать функцию манипулятор без параметров. Форма объявления функции - манипулятора функции следущая:

	ostream &manip_name(ostream &stream)
	{
	  //Коды программы
	  return stream;
	}

Это манипулятор вывода. Для создания функции - манипулятора ввода надо заметить поток ostream на istream. Пример создания манипулятора с именем left10:

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

ostream& left10(ostream &stream)
{
  stream.setf(ios::left);
  stream << setw(10);
  return stream;
}
main (void)
{
  cout << 12 << left10 <<15 << 17 <<"\n";
  return 0;
}

Задания к выполнению

  1. Считайте файл чисел с плавающей точкой, составьте из пар считанных чисел комплексные числа и выведите комплексные числа и сохранить их в новом файле.
  2. Перегрузите операцию << для класса , который будет прость ввести любую строку, а затем должен опять вывести её на экран но без больших букв и цифр
  3. Постройте несколько функций для запроса и чтения различного вида информации. Простейший пример - функция y_or_n() (Которая просит ввести Yes\No). Идеи: почтовый адрес, дата, личные данные и т.д. Постарайтесь сделать их защищенными от неправильного ввода.
  4. Напишите программу, которая печатает (1) все буквы в нижнем регистре, (2) все буквы, (3) все буквы и цифры, (4) все символы, которые могут встречаться в идентификаторах C++ на вашей системе, (5) все символы пунктуации
  5. Реализуйте стандартную библиотеку ввода/вывода C () с помощью стандартной библиотеки ввода/вывода C++ () (достаточно printf и scanf).
  6. Реализуйте стандартную библиотеку ввода/вывода C++ () с помощью стандартной библиотеки ввода/вывода C () (достаточно cout и cin).
  7. Реализуйте класс, для которого [] перегружено для реализации случайного чтения символов из файла.
  8. Как Задание 7, только сделайте, чтобы [] работало и для чтения, и для записи. Подсказка: сделайте, чтобы [] возвращало объект "дескрипторного типа", для которого присваивание означало бы присвоить файлу через дескриптор, а неявное преобразование в char означало бы чтение из файла через дескриптор.
  9. Как Задание 8, только разрешите [] индексировать записи некоторого вида, а не символы.
  10. Создайте свой манипуляторы которые будут выполнять 1)вывод всех символов большими а чискл в OCT формате 2)вывод всех символов маленькими и замено пробелов на # 3)вывод всех чисел в HEX формате и не выводить пробелов
  11. Разработайте и реализуйте операцию ввода по сопоставлению с образцом. Должна быть возможность попробовать сопоставить со вводом несколько образцов для нахождения наиболее близкого к образцу. Можно было бы вывести класс ввода по образцу из istream.(примеры образцов десятичное число , имя пользователя , пароль из цифр и символов)
  12. Придумайте (и реализуйте) вид образцов, которые намного лучше чем в 11.
  13. Постройте несколько функций для запроса и чтения различного вида информации. Простейший пример - функция y_or_n() (Которая просит ввести Yes\No). Идеи: Почтовый адрес, дата, личные данные. Постарайтесь сделать их защищенными от дурака.
  14. Напишите программу которая будет просить ввести строку символов , после этого он печатает её на экране 1) все буквы в нижнем регистре , 2) все буквы в большом регистре , 3) все числа в строке выводить в HEX формате , 4) вывод с заменой всех пробелов на символ #
  15. Реализуйте стандартные функции printf(c помощью cout) и cin(с помощью scanf) так, чтобы они могли использоваться одновременно.
  16. Реализуйте стандартные функции scanf(c помощью cin) и cout(с помощью printf) так, чтобы они могли использоваться одновременно.
  17. Написать программу конвертор чисел из одной системы исчесления в другую.(HEX,BIN,OCT)
  18. Написать программу которая создаёт массив размером [256] элементов и заполняет его случайным образом числами от 1 до 1000 . После этого вывести все числа на экран в несколько форматированых столбцов , при этом в первом столбце выводить числа в DEC формате , во втором в HEX формате , в третьем в OCT формате , четвёртый опять в DEC и т.д. до конца.
  19. Создать класс который при инициализации (в конструкторе) получает имя файла с текстовой строкой , а при уничтожении (в деструкторе) сохраняет строку в другом файле , убрав при этом все пробелы, обрезав у всех дробных чисел количество знаков после запятой до двух и заменив все маленькие буквы на большие.
  20. Считайте файл с комплексными числами , составьте из каждого числа пару простых чиел и сохраните их в новом файле.
  21. Определите тип name_and_address (имя_и_адрес). Определите для него << и >>. Скопируйте поток объектов name_and_address.
  22. Перегрузите операцию << для класса , который будет просить ввести любую строку, а затем должен опять вывести её на экран но без маленьких букв
  23. Перегрузите операцию >> для класса , прегруженная функция должна передать строку из случайных символов ,а класс должен вывести всю строку форматировано на экран и без пробелов
  24. Перегрузите операцию >> для класса , прегруженная функция должна предать строку из случайных символов ,а класс должен вывести всё строку большими буквами ,а все числа в строке вывести в HEX формате

Пример выполнения задания (╧24)

#include <iostream.h>
#include <stdlib.h>
#include <iomanip.h>
class array{
public:
  array();
  char a[100];
  void operator>>(ostream &stream);
};
class probasta{
   array ar;
 public:
  void operator>>(ostream &stream);
  void operator<<(array tst);
};
void main(void)
{
  array ar_test;
  cout << "\nСтрока в оригинале:\n\n";
  ar_test >> cout;
  cout << "\n\nОбработаная строка:\n\n";
  probasta test;
  test << ar_test;
  test >> cout;
}
void array::array()
{
  randomize();
  for(int i=0;i<100;i++){
   a[i]=random(59);
   if(a[i]<24)a[i]=32;
   else a[i]+=64;
   
   }
  randomize();
}
void array::operator>>(ostream &stream)
{
  for(int i=0;i<100;i++)
    stream << a[i];
}

void probasta::operator>>(ostream &stream)
{
  for(int i=0;i<100;i++)
  {
    if((i==30)||(i==60)||(i==90)) stream << "\n";
    if(ar.a[i]!=32) stream << ar.a[i];
  }
}
void probasta::operator<<(array tst)
{
  ar=tst;
}


НазадОглавлениеВперед
КаталогИндекс раздела