Использование манипуляторов
Манипуляторы – специальные функции, возвращающие модифицированные данные потока. В большинстве случаев их использование позволяет форматировать данные, как при выводе, так и в оперативной памяти.
Для их использования необходимо вместо файла 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 [ ] при освобождении памяти, занятой массивом, обязательны. Их отсутствие может привести к непредсказуемым результатам.