Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Вариант_№29.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
403.97 Кб
Скачать

Вывод для встроенных типов

Файл заголовков iostream.h содержит объявление объекта вида:

ostream cout;

Класс ostream определяет оператор вывода << для встроенных типов:

class ostream

{ // …

public: // общедоступные функции

ostream & operator << (char); // символ

ostream & operator << (char*); // символьная строка

ostream & operator << (int i); // целый

ostream & operator << (long); // длинный целый

ostream & operator << (double); // двойной действительный

ostream & put(char); // символ

}

Операция <<, называемая вставкой, заменяет функцию вывода printf(). Левый операнд – это объект cout типа класса ostream. Правый операнд может иметь любой тип, для которо­го определен вывод потоком для встроенных типов.

Функция-оператор << возвращает обращение по адресу, для которого она была вызвана, так что можно применить другой оператор ostream, т.е. можно строить цепочки операций вывода в порядке слева направо.

Например:

int i, k=234; double d ; char ch='A';

cout<<”Значение k=” << k <<’\n’; // в конце символ перевода строки

cin>> i >> d; // ввод данных i, d

cout<<”i=”<<i<<” d=”<<d<<’\n’; // вывод значений i, d

cout<<”ch=”<<ch; // вывод символа A

Пример 1.

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

#include<iostream.h> // подключение библиотек ввода-вывода

void main()

{ int i;

char str[ ]=”Пример вывода в С++\n”;

cout<<”Вывод строки”<<str;

cout<<”Введите целое и длинное целое число: “;

long l; // переменная описывается перед первым использованием

cin>>i>>l; //ввод данных

cout<<”i=”<<i<<” l=”<<l<<’\n;

cout<<”Введите строку: ”;

cin>>str;

cout<<”Введена строка: ”<<str;

}

Замечание. Можно также использовать любые библиотечные функции ввода-вывода языка С (printf(), scanf() и др.). Кроме того, в другом контексте преопределенные операторы << и >> задают операции сдвига.

Пример 2.

Встроенные типы вставок (вывода данных). Целые типы преобразуются по правилам (по умолчанию) для printf (если эти правила не изменены путем установки флагов ios).

#include<iostream.h> // подключение библиотек ввода-вывода

#include<stdio.h> // для printf

#include<conio.h> // для консольных функций

void main()

{ int i=5; int *pi=&i; long l=12345678; double d=345.6789; char ch='A';

clrscr(); // чистка экрана результатов

cout<<”Вывод с помощью функции printf():\n”);

printf(“i=%d адрес i pi=%#x l=%ld d=%.4f ch=%c\n”, i,pi,l,d,ch);

cout<<”Вывод с помощью потока cout:\n”;

cout << ”i=”<< i << ” адрес i=” << &I << ” l =” << l << ” d=” <<d;

cout<<” ch=”<<ch<<'\n';

getch(); // задержка экрана результатов

}

Результаты программы:

Вывод с помощью функции printf():

i=5 адрес i pi=0xfff4 l=12345678 d=345.6789 ch=A

Вывод с помощью потока cout:

i=5 адрес i=0x8f61fff4 l=12345678 d=345.6789 ch=A

Управление вводом-выводом

Символьные извлечения.

Для типа char действие операции >> состоит в пропуске пробельных символов и чтения следующего (непробельного) символа. Если требуется про­честь следующий символ (любой), то можно использовать одну из функций-эле­ментов get() класса istream:

сhar ch;

cin.get(ch); // ch устанавливается на следующий символ потока,

// даже если это пробельный символ.

Следующий вариант get позволяет управлять числом извлекаемых симво­лов, их размещением и оконечным символом:

get(char* buf, int max, int term=’\n’).

Эта функция считывает символы из входного потока в символьный мас­сив buf до тех пор, пока не будет считано max -1 символов, либо пока не встре­тится символ, заданный term, в зависимости от того, что будет раньше. Завер­шающий пустой символ (нуль-байт – ‘\0’) добавляется автоматически. По умолчанию око­нечным символом (терминатором), который не требуется задавать, является ‘\n’. Сам терминатор в массив buf не считывается и из входного потока istream не удаляется. Массив buf должен иметь размер не менее max символов.

Пример 3.

Ввод строки цифр и преобразование их в целое число типа int с помощью функции atoi(s) и вывод числа в 10-ом, 16-ом, 8-ом форматах с использованием идентификаторов dec, hex, oct, вставленных в поток вывода для управления форматом выходного потока, endl аналог '\n'. (см. Манипуляторы).

#include<iostream.h> // подключение библиотек ввода-вывода

#include<conio.h> // для консольных функций

#include<stdlib.h> // для функции atoi()

const int size=35; // размер буфера строки

void main()

{ clrscr();

int value; // переменная для числа

char s[size]; // буфер строки

cout<<"Value= ";

cin.get(s, size,'\n'); // ввод строки числа

value=atoi(s); // преобразование строки в число

cout<<"Decimal="<<dec<<value<<" Hexadecimal=0x"<<hex<<value

<<" Octal=0"<<oct<<value<<endl;

getch();

}

Результаты программы:

Value=123

Decimal=123 Hexadecimal=0x7b Octal=0173

Замечание. Для ввода строки вместо функции cin.get(s, size,'\n'); можно использовать cin>>s. Этот оператор сработает, но если пользователь введет бо­лее 34 символов, оператор ввода продолжит запись за пределами буфера s, при этом, возможно, данные и код, располагающиеся за буфером, будут уничтоже­ны. Такая операция может привести к краху системы!

Пример 4.

Использование функции get для безопасного чтения строк.

#include<iostream.h>

void main()

{ char s[35]; // буфер строки

char c; // переменная символа

cout<<"Введите строку не более 34 символов:\n";

cin.get(s, 35); // пропущен 3-й аргумент по умолчанию '\n'

cout<<"Вы ввели строку: "<<s<<endl;

if(cin.get(c) && c!='\n') // если следующий символ не '\n', то вывод

cout<<"Достигнута максимальная длина строки\n";

}

При вводе строки длиной более 34 символов она будет усечена и ввод бу­дет безопасным. Одна проблема все же остается. Символ '\n' или другой сим­вол, завершающий ввод, остается в потоке и должен быть прочитан еще одним оператором cin.get(), как показано последним оператором if. Если cin.get() не читает символ '\n', ввод будет усечен. Этот факт необходимо учитывать при на­писании программ.

Проблему непрочитанного символа '\n' можно решить с помощью метода cin.getline() с тремя параметрами (совпадет с get()), при этом символ раздели­тель '\n' также помещается в принимающую строку символов (s).

Для ввода неформатированных и непреобразованных двоичных данных используется функция cin.read((char*)&x, sizeof(x)).

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

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

Ширина вывода.

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

int ios::width(int w); // устанавливает поле шириной w символов и воз­вращает предыдущую ширину,

int ios::width(); // возвращает предыдущую ширину, не внося из­менений.

По умолчанию width=0, то есть вывод выполняется без заполнителей. При w≠0, если длина числа меньше w используются заполнители, иначе выводится фактическое число без усечения.

Например:

int i=123;

int oldw=cout.width(6);

cout<< i; // вывод будет 123 (перед числом 3 пробела), затем width=0

cout.width(oldw); // восстановление предыдущей ширины width=6

После каждой форматной вставки ширина обнуляется, например:

int i, j;

cout.width(4);

cout<< i <<" "<< j <<;

Здесь i будет выведено четырьмя символами, однако пробел и j будут иметь минимально необходимое число символов.

Заполнители и дополнение вправо и влево.

Символ-заполнитель и направление дополнения зависят от установок вну­тренних флагов, отвечающих за эти параметры.

По умолчанию символом-заполнителем является пробел. Изменить данное умолчание позволяет функция fill:

int i=123;

cout.fill ("*");

cout.width(6);

cout<< i; // на экран будет выведено ***123

По умолчанию устанавливается выравнивание по правому краю (дополне­ние символами-заполнителями). Это можно изменить функциями setf и unsetf:

int i=56;

cout.width(6);

cout.fill ("#");

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

cout<< i; // на экране: 56####

Второй аргумент сообщает setf, какие биты флага должны быть установ­лены. Первый аргумент сообщает, в какие именно значения устанавливаются эти биты.

Можно также использовать манипуляторы setfill, setiosflags, resetiosflags.

Манипуляторы.

Это специальные операции (похожие на функции) для более простого из­менения ширины и других параметров форматирования. Для их использования программа должна иметь строку:

#include<iomanip.h>

Манипуляторы принимают в качестве аргумента ссылку на поток и воз­вращают ссылку на тот же поток. Поэтому манипуляторы могут объединяться в цепочку вставок (или извлечений из потока) для того, чтобы изменять состоя­ние потока в виде побочного эффекта, без фактического выполнения каких-либо вставок или извлечений. В таблице ниже в столбце синтаксис задано направле­ние потока: входной – ins >>, выходной – outs <<.

Таблица

Манипулятор Синтаксис Действие

Установка флага форматирования с преобразованиями:

dec outs << dec 10-ым ins >> dec

hex outs << hex 16-ым ins >> hex

oct outs << oct 8-ым ins >> oct

ws ins >> ws Извлечение пробелов

endl outs << endl Вставка символа новой строки

и очистка потока

ends outs << ends Вставка конечного нулевого

символа в строку

flush outs << flush Очистка ostream

setbase(int) outs << setbase(n) Установка системы счисления

(0, 8, 10, 16). 0 это по умолча-

нию 10-ая с.с. при выводе и

правила С для литералов це-

лых чисел при вводе

resetiosflags(long) ins>>resetiosflags(1) Очистка битов в ins или outs

outs<<resetiosflags(1) аргументом 1

setiosflags(long) ins >> setiosflags(1) Установка битов в ins или outs

outs << setiosflags(1) аргументом 1

setfill(int) ins >> setfill(n) Установка символа

outs >> setfill(n) заполнителя в n

setprecision(int) ins >> setprecision(n) Установка точности представле-

outs>>setprecision(n) ния чисел с плавающей точкой,

равной n разрядам

setw(int) ins >> setw(n) Установка ширины поля

outs << setw(n) в значение n

Пример 5.

Применение функций и манипуляторов форматирования вывода в про­грамме.

#include<iostream.h>

#include<conio.h>

#include<iomanip.h>

void main()

{ clrscr();

int i=36, j=45;

cout<<"Вывод с установленной шириной поля 5 числа i:\n";

int oldw=cout.width(5); // установка ширины поля вывода

cout<< i <<'\n';

cout<<"После каждой вставки формата ширина поля=0:\n";

cout<< " oldw=" << oldw << '\n';

cout<< i << '\n';

cout<< "Установка поля 5 влияет только на 1-ю переменную:\n";

cout.width(5);

cout<< i << " " << j << '\n';

cout<< "Манипулятор setw(5) упрощает вывод переменных:\n";

cout<< setw(5) << i << setw(5) << j << '\n';

cout<< "Манипуляторы dec, hex, oct изменяют сист. счисл. \n";

cout<< "(оставляя эти изменения в силе) — вывод i:\n";

cout<< dec << i << " " << hex << i << " " << oct << i <<endl;

cout<< "Манипулятор endl аналог '\n' очищает поток"<<endl;

cout<< "i= " << i <<endl;

cout<< "Заполнитель пробел можно заменить на *"<<endl;

cout.fill ( '*' ); // задание символа заполнения функцией fill

cout<< setw(6) << i << endl; // установка ширины поля 6 числа i

cout<< "Выравнивание можно изменить функцией setf:"<<endl;

cout.width(6);

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

cout<< "i= " << i <<endl;

getch();

}

Вывод чисел с плавающей точкой.

Большие и малые числа выводятся в экспоненциальном формате (е, Е), а не фиксированном. Например, число 1234567.8 печатается 1.2345678Е+07.

Числа с нулевой дробной частью печатаются как целые. Например, число 95.0 печатается 95.

Для вывода десятичных чисел в фиксированном формате можно использо­вать следующие операторы:

cout.setf(ios::fixed, ios::floated);

cout.setf(ios::showpoint);

Первый вызов функции setf обеспечивает печать чисел в фиксированном, а не экспоненциальном представлении. Второй вызов задает печать десятичной точки, даже если дробная часть числа равна 0.

Управление числом десятичных позиций при выводе выполняется с помо­щью манипулятора установки точности:

cout<< setprecision(2) << x;

например, вместо числа 16.38567 печатается 16.39.

Пример 6.

Если отсутствует переназначение, то ввод с клавиатуры отображается на экран. Следующая программа копирует cin в cout.

#include<iostream.h>

void main()

{ char ch;

while (cin >> ch)

cout << ch;

}

Обратите внимание, что cin >> ch может рассматриваться как булевское выражение. Этот эффект стал возможен благодаря определениям в классе ios. А именно, такие выражения как (cout) или (cin >> ch) рассматриваются как ука­затель на переменную, значение которой определяется кодом ошибки пото­ка. Нулевой указатель (трактуемый как "ложь") индицирует ошибку в потоке, а не­нулевой указатель ("истина") означает ее отсутствие. Можно использовать опе­рацию отрицания (!), в этом случае (!cout) будет "истина" при возникнове­нии ошибки в потоке cout и "ложь", если они отсутствуют:

if (!cout) errmsg("Output error!");

cin — это входной поток, подключенный к стандартному выводу. Он мо­жет правильно обрабатывать все стандартные типы данных. Как известно, в С вывод подсказки (приглашения) без символа новой строки ('\n') в стандартный выходной поток stdout требует обращения к fflush(stdout), чтобы эта подсказка могла появиться. В С++ обращение к cin автоматически очищает cout.

Рассмотрим примеры простых программ на С++ с отличиями от С-про­грамм.

Пример 7.

Применение констант и встроенных функций (inline).

#include<iostream.h>

const float pi=3.14159;

inline float area (const float r) { return pi*(r)*(r); }

void main()

{ float radius;

cout << "Введите радиус круга: ";

cin >> radius;

cout << "Площадь круга= " << area (radius) << '\n';

}

Идентификатор константы ведет себя как обычная переменная (т.е. ее об­ластью действия является блок, в котором она определена) за исключением того, что она не может находиться в левой части оператора присваивания. Дирек­тива #define является морально устаревшей для С++.

Ключевое слово inline указывают компилятору, что, если возможно, следу­ет вставлять код в том месте, где он встретил обращение. Это эквивалентно ма­крорасширению и используется там, где необходимо ликвидировать накладные расходы, связанные с вызовом функции. Рекомендуется применять встроенную функцию, составленную из одной-двух строк.

Ссылки и указатели как параметры функции.

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

Пример 8.

Переставить значения двух аргументов в функции с указателями.

void swap1 (int *a, int *b)

{ int tmp;

tmp=*a; *a=*b; *b=tmp;

}

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

swap1(&i, &j); // i, j — аргументы функции

В С++ можно использовать в функции ссылки (&) на изменяемые парамет­ры, а в теле функции и при вызове применяются имена параметров и аргумен­тов:

void swap2 (int &a, int &b)

{ int tmp=a; a=b; b=tmp; }

Вызов функции:

swap2 (i, j);

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]