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

Манипуляторы – специальные функции, возвращающие модифицированные данные потока. В большинстве случаев их использование позволяет форматировать данные, как при выводе, так и в оперативной памяти.

Для их использования необходимо вместо файла iostream.h подключить заголовочный файл iomanip.h (манипуляторы для вывода потоками).

Рассмотрим работу некоторых манипуляторов на конкретном примере.

#include<iomanip.h>

main()

{

int a = 157;

double b = 1.55555;

cout << setw(10) << a << endl;

/* Манипулятор setw(n) – устанавливает ширину поля, т.е. n позиций, для вывода объекта. На экране объект а будет выводиться с 8-й позиции, первые 7 позиций – пустые: 157 (заполнение пробелами неиспользуемой части). Действует только для следующего за ним объекта. */

cout << setw(10) << setfill(‘z’) << a << endl;

/* Манипулятор setwfill(kod) – устанавливает заполнитель пробелов, задан­ный символом или его кодом (можно было указать 122 – код символа 'z'). На экране: zzzzzzz157. Действует до изменения или отмены setwfill(0) .*/

cout << oct << a << endl;

/* Манипулятор oct – выполняет преобразование объекта в 8-ричную форму представления. На экране: 235 */

cout << hex << a << endl;

// hex – преобразует объект в 16-ричную форму. На экране: 9d

cout << dec << a << endl;

// dec – преобразует обратно в 10-тичную. На экране: 157

cout << b << endl; // На экране: 1.55555

cout << setprecision(3) << b << endl;

/* setprecision(n) – устанавливает n значащих цифр после запятой с учетом точки или без нее, в зависимости от системы программирования. На экране:

1.56 или 1.556 */

return 0;

}

 

Флажки

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

Установить флажок позволяет функция setiosflags(ios :: flag);

Снять флажок позволяет функция resetiosflags(ios :: flag);

Причем можно установить сразу несколько флажков, используя для этого побитовую операцию «|» (поразрядное ИЛИ) для их объединения в одну группу.

Следующий пример показывает приемы работы с некоторыми флажками механизма вывода потоками.

#include<iostream.h>

#include<iomanip.h>

#include<conio.h>

void main(void) {

int a = 157;

cout<<setiosflags(ios :: showbase)<<a<<“ “<<oct<<a<< “ “

<<hex<<a<< endl;

/* showbase – показать, в какой системе счисления выводится число. На экране: 157 0235 0х9d */

double a1 = 12.99, a2 = 15;

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

/* showpoint – печатать десятичную точку, fixed – выводить в форме с фиксированной десятичной точкой */

<< setprecision(2) << setfill(‘*’) << setiosflags(ios :: right)

// right – выравнивать вывод по правому краю (по левому – left)

<< “ a1 “ << setw(10) << a1

<< “ a2 “ << setw(10) << a2 << endl;

// На экране: a1 *****12.99 a2 *****15.00

double pi = 3.14159;

cout << “ Pi “ << setw(15) << setfill(‘_’)

// Символ заполнения ‘_’ – знак подчеркивания

<< setiosflags(ios :: showpos | ios :: scientific)

<< setprecision(5) << pi << endl;

/* showpos – явно показать знак «+», scientific – вывод в форме с плавающей десятичной точкой. На экране: Pi _ _ _ +3.14159e+00 */

}

 

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

 

16.3. Проблема ввода-вывода кириллицы в среде Visual C++

Работа в среде Visual C++ 6.0 (в режиме консольных приложений) сопряжена с определенными неудобствами. Например, попытка вывести фразу на русском языке, как стандартными функциями вывода, так и с помощью ввода-вывода потоками, терпит неудачу. Создадим в среде Visual C++ 6.0 консольное приложение и наберем следующий текст:

#include <iostream.h>

int main()

{

cout << "Welcome to C++ !" << endl;

cout << "Добро пожаловать в C++ !" << endl;

return 0;

}

В результате на экране получим нечто следующее:

Welcome to C++ !

─юсЕю яюцрыютрЄ№ т C++ !

Press any key to continue

То есть вместо фразы на русском языке получается бессмысленный набор символов. Это вызвано различными стандартами кодировки символов кириллицы в операционных системах MS DOS и Windows.

Весь ввод-вывод в консольном окне идет в кодировке стандарта ASCII. Данный стандарт является международным только в первой половине кодов, т.е. для кодов от 0 до 127, а вторая половина кодов от 128 до 255 предназначена для национальных шрифтов. Так, например, в бывшем СССР помимо альтернативной кодировки ГОСТа (Alt), использовались – основная кодировка ГОСТа (Mai), болгарская кодировка (MIC), кодировка КОИ-8 (KOI), у которых символы кириллицы имеют разные коды. Сейчас в России – альтернативная кодировка ASCII.

Текст же в исходных файлах, набираемый в текстовом редакторе Visual C++, имеет кодировку в стандарте ANSI. Данный стандарт в первой половине совпадает с альтернативной кодировкой ASCII, а во второй – отличается, так как разработчики Visual решили, что консольное приложение должно имитировать работу в среде MS DOS и оставили альтернативную кодировку ASCII.

Для нормального вывода строки, содержащей буквы русского алфавита, надо использовать функцию CharToOem, предназначенную для преобразования символов с кодировкой ANSI в кодировку ASCII. Аналогично, если в программе есть консольный ввод текста и этот текст в дальнейшем надо сохранять в документах (файлах) с кодировкой ANSI, то перед сохранением нужно воспользоваться функцией обратного преобразования – OemToChar. Эти функции декларированы в заголовочном файле windows.h.

С учетом сказанного выше можно предложить следующую программу корректного вывода информации на русском языке:

#include <iostream.h>

#include <windows.h>

char* Rus(const char* text);

char bufRus[255];

int main()

{

char s[] = "Минск!", ss[100];

cout << Rus("Город ") << Rus(s) <<endl;

cout << Rus("Введи строку:");

cin >> ss;

cout << Rus(" Строка: ") << ss << endl;

return 0;

}

char* Rus (const char* text)

{

CharToOem(text, bufRus);

return bufRus;

}

 

Результат программы может быть следующим:

Город Минск!

Введи строку: Москва!

Строка: Москва!

Таким образом, для решения проблемы с русским языком в консольном выводе Visual C++ 6.0 создана небольшая функция Rus, которая обращается к функции CharToOem, передает ей для преобразования полученный через свой параметр текст на русском языке и возвращает указатель на преобразованную строку. В качестве временного хранилища используется глобальный символьный массив bufRus. Использовать функцию просто: везде вместо строковых объектов (строковых констант и переменных) в программах нужно писать Rus(строковый объект).

Непосредственное использование функции CharToOem, например, в стандартных функциях вывода данных недопустимо, так как возвращает результат типа BOOL, а результат преобразования размещает по адресу своего второго аргумента. Поэтому и была создана эта небольшая пользовательская функция, которая имеет единственное ограничение: функцию Rus нельзя использовать в цепочке операций << более одного раза, так как для различных компиляторов и режимов оптимизации может быть получен неверный результат.

Операции new и delete

В языке С++ для захвата и освобождения памяти используется более простой механизм – операции new и delete. Рассмотрим эти операции на простых примерах:

1) type *p = new type (значение); – захват участка памяти размером sizeof(type), путем установки на него указателя, и запись в эту область указанного значения;

. . .

delete p; – освобождение захваченной памяти.

2) type *p = new type[n]; – захват памяти на n последовательно размещенных объектов, возвращает указатель на начало участка ОП размером n*sizeof(type); используется для создания массива;

. . .

delete []p; – освобождение всей захваченной памяти.

Следует заметить, что операция delete не уничтожает значения, находящиеся по указанным адресам, а дает компилятору разрешение использовать ранее занятую память в дальнейшем.

Квадратные скобки в операции delete [ ] при освобождении памяти, занятой массивом, обязательны. Их отсутствие может привести к непредсказуемым результатам.