Потоковый ввод данных числового типа
Для начинающих программистов проще всего организовать в программе ввод числовой информации из буфера потока, связанного с так называемым стандартным устройством ввода (stdin). Данные в этом буфере оказываются в тот момент, когда программа обращается к пользователю и ждет окончания набора затребованных числовых значений с клавиатуры. Программа может запросить одно или несколько значений:
cin >> d;
...........
cin >> x1 >> x2 >> x3;
Первая строка соответствует запросу на ввод значения единственной переменной d. Следующая строка программы представляет запрос на ввод трех числовых значений, первое из которых будет присвоено переменной x1, второе значение предназначается для переменной x2, третье значение – для переменной x3. В ответ на запрос программы пользователь должен набрать на клавиатуре затребованные числа, разделяя их, по крайней мере, одним пробелом. Набор строки завершается нажатием клавиши Enter. Количество числовых значений, набираемых пользователем в пределах строки, может оказаться как меньше, так и больше, чем требуется программе. В первом случае продолжение программы задержится до тех пор, пока пользователь не введет дополнительные строки с недостающими значениями. Если пользователь наберет слишком много значений в вводимой строке, то лишние числовые данные сохранятся в буфере ввода и будут переданы программе при выполнении следующего оператора cin.
Тип набираемого числового значения и его величина должны соответствовать типу переменной, в которую это значение должно быть введено. Забота об этом целиком возлагается на пользователя.
Для обеспечения потокового ввода к программе следует подключить заголовочный файл iostream.h:
#include <iostream.h>
int main()
{ int i;
float f;
double d;
..........
cin >> i >> f >> d;
В переменные типа char или unsigned char из потока числовые значения ввести невозможно, т.к. они в данном случае воспринимаются системой не как числовые данные, а как символьные. В такие переменные попадет только первый символ набранного значения.
Форматный ввод
Гораздо более сложным для начинающих программистов является ввод числовых данных, организуемый с помощью функции scanf, использующей так называемую форматную строку:
#include <stdio.h>
int main()
{ int i;
float f;
double d;
..........
scanf("%d %f %lf",&i,&f,&d);
Строка вводимых данных поступает со стандартного устройства ввода (stdin), которым по умолчанию считается клавиатура. Завершение набора строки ввода – нажатие клавиши Enter.
Первый аргумент функции scanf представляет форматную строку, управляющую процессом преобразования числовых данных, набранных пользователем в строке ввода, в машинный формат, соответствующий типам переменных, адреса которых указаны вслед за форматной строкой. Числовые значения в строке ввода рекомендуется разделять одним или несколькими пробелами.
В приведенном примере переменной i (в списке ввода указан ее адрес – &i), объявленной с помощью спецификатора типа int, соответствует форматный указатель %d. Это означает, что первым числовым значением в строке ввода может быть только целое десятичное число со знаком (d – от decimal, десятичный). Вещественной переменной f типа float в форматной строке соответствует указатель %f. Это означает, что второе числовое значение в строке ввода должно принадлежать диапазону, предусмотренному для коротких вещественных данных. Для переменной d типа double использован форматный указатель %lf (l – от long).
Как правило, количество форматных указателей, перечисленных в первом аргументе функции scanf, должно совпадать с количеством адресов переменных, следующих за форматной строкой. Исключение составляет случай, когда форматный указатель предписывает программе пропустить очередное значение из введенной строки. В этом случае количество адресов в списке ввода уменьшается соответствующим образом. Например:
scanf("%d %*l %lf",&i,&d);
При выполнении такого оператора ввода программа проигнорирует второе числовое значение, набранное пользователем. Конечно, при ручном наборе вводимых значений, нелепо заставлять пользователя набирать данные, которые программе не понадобятся. Но такая возможность может оказаться полезной, когда строка ввода поступает не с клавиатуры, а из других источников (считана с диска, сформирована другой программой в оперативной памяти).
Вообще говоря, функция scanf возвращает числовое значение, равное количеству правильно обработанных полей из строки ввода. Это полезно помнить при организации проверки правильности ввода, т.к. сообщения об ошибках ввода функция scanf не выдает, но после первой же ошибки прерывает свою работу.
Основная сложность в овладении тонкостями ввода, управляемого списком форматных указателей, заключается в многообразии последних. В самом общем виде числовой форматный указатель, используемый функцией scanf, представляется как следующая последовательность управляющих символов и дополнительных признаков:
%[*][ширина][{l|h|L}]{d|i|u|o|x|X|f|e|E|g|G}
Квадратные скобки здесь означают, что соответствующий элемент форматного указателя может отсутствовать. В фигурных скобках указаны символы, один из которых может быть выбран. Обязательными элементами любого форматного указателя являются начальный символ % и последний символ, определяющий тип вводимого значения.
Символ * после начального символа является указанием о пропуске соответствующего значения из строки ввода. Необязательное, и, как правило, не используемое при вводе, поле ширина задает количество символов во вводимом значении. Дополнительные признаки l, h и L уточняют длину машинного формата соответствующей переменной (l, L – long; h – short). Значение последнего обязательного символа форматного указателя расшифровано в табл. 4.3.
Таблица 4.3
Символ формата | Допустимое значение в строке ввода |
d | целое десятичное число со знаком |
i | целое число |
u | целое число без знака |
o | целое восьмеричное число без знака |
x,X | целое шестнадцатеричное число без знака |
f | вещественное число |
e,E | вещественное число |
g,G | вещественное число |
Форматный ввод также как и потоковый не позволяет вводить числовые значения в переменные типа char. Дело в том, что минимальная длина числового значения вводимого с помощью функции scanf – 2 байта. И значение введенного старшего байта затирает в памяти еще один байт вслед за переменной типа char. Заметить такую ошибку удается не каждому, но на работу программы такой ввод может повлиять довольно серьезно. Поэтому возьмите за правило – в однобайтовые переменные типа char числовую информацию вводить нельзя.
Вывод числовых результатов
Форматный вывод
Форматный вывод числовых результатов на стандартное устройство вывода (stdout), которым по умолчанию является экран дисплея, осуществляется с помощью функции printf. Например:
#include <stdio.h>
int main()
{ int i;
float f;
double d;
..........
printf("%d %f %lf", i+1, f, f*d);
Ее аргументы напоминают по форме обращение к функции scanf с той лишь разницей, что список вывода составляют не адреса переменных, а арифметические выражения, значения которых предварительно будут подсчитаны, а потом выведены в соответствии с использованными форматными указателями.
Для преобразования числовых данных из машинного формата используются форматные указатели, общий вид которых содержит расширенный набор признаков:
%[флажки][ширина][.точность][{l|h|L}]{d|i|u|o|x|X|f|e|E|g|G}
Поле ширина определяет количество знакомест на экране, где будет размещен выводимое значение. Как правило, его задают с некоторым запасом, чтобы смежные значения не сливались друг с другом. Выводимое число прижимается младшим разрядом к правой границе указанного поля. Это обеспечивает общепринятый способ вывода числовых таблиц, когда в столбцах одноименные разряды чисел располагаются друг под другом. Если заданная ширина меньше, чем это требуется для выводимого значения, то оно все равно будет выведено полностью, но стройность колонок в таблицах при этом будет нарушена.
Поле флажков может содержать до четырех управляющих символов из набора [–,+,пробел,0,#]. Символ "минус" устанавливает прижим выводимого значения к левой границе выделенного поля (по умолчанию действует правый прижим). Символ "плюс" устанавливает обязательный режим вывода знака числа (даже если оно положительно). Символ "пробел" устанавливает такой режим, при котором вместо знака "+" выводится пробел. Символ "нуль" устанавливает режим вывода чисел, при котором старшие незначащие позиции поля вывода заполняются нулями.
Символ # влияет на формат вывода восьмеричных, шестнадцатеричных и вещественных чисел. При его использовании перед восьмеричными числами выводится лидирующий нуль, перед шестнадцатеричными числами – префикс 0x или 0X. Для форматов f, e, и E обязательно отображается десятичная точка после целой части (по умолчанию, числа, у которых дробная часть равна 0, выводятся без десятичной точки). Для форматов g и G не удаляются лидирующие нули и всегда выводится десятичная точка.
.
Необязательное поле точность задает для целочисленных значений обязательное количество цифр (если число меньше, то перед его старшим разрядом добавляется необходимое количество нулей). Например, вывод целочисленного значения –5 по формату %8.4d выделяет в строке вывода поле из восьми символов, на котором первые три позиции заполнены пробелами, а следующие пять символами –0005.
Для данных вещественного типа поле точность определяет количество цифр в дробной части числа. Не забывайте о количестве значащих цифр, хранение которых обеспечивает тот или иной тип данных. Например, если переменной типа float присвоить значение 3.14159265, то на выводе по формату %10.8f мы увидим результат 3.14159274. Двум последним цифрам результата доверять нельзя, т.к. формат float обеспечивает хранение 7-8 десятичных цифр.
Разница между форматами %0x и %0X заключается в том, что в первом случае шестнадцатеричная запись числа формируется из малых букв [a,b,c,d,e,f], а во втором случае – из больших букв [A,B,C,D,E,F].
Для вывода однобайтовых целочисленных данных со знаком (типа char) можно пользоваться одним из следующих форматов – %o, %0x, %0X, %i, %d, %ho, %hx, %hX, %hi, %hd. Для вывода однобайтовых целых без знака наряду с перечисленными указателями допустим формат %u. Однако следует иметь ввиду, что однобайтовые значения расширяются до двухбайтовых, сохраняя знак числа. Поэтому попытка вывести однобайтовое значение 127 по формату %u приведет к правильному результату. Но если мы по такому же формату выдадим число -5, то результатом будет число 65531 (дополнение до максимального двухбайтового числа).
Вывод числовых результатов вещественного типа предусматривает две формы отображения – с фиксированной запятой (форматные указатели %f и %lf) или с плавающей запятой (форматные указатели %e и %E). Форматные указатели %g и %G предлагают системе самой выбрать один из этих форматов, который окажется более компактным для выводимого значения. Большая или маленькая буква в форматных указателях с плавающей запятой приводит к тому, что порядку числа предшествует большая или маленькая буква "e".
При форматном выводе числовых результатов бывает удобно сопроводить их какой-либо пояснительной подписью. Обычно текст такого пояснения включают в форматную строку. Все символы, которые не являются принадлежностью форматных указателей, автоматически переносятся в выводную строку. Например, при выполнении следующих операторов:
x1=127; x2=-350;
printf("x1=%d x2=%d",x1,x2);
на экране дисплея появится строка:
x1=127 x2=-350
Если мы хотим расположить выводимую информацию на экране дисплея с начала следующей строки, то в начале форматных указателей обычно вставляют управляющий символ "\n":
printf("\nx1=%d x2=%d),x1,x2);
Такой же управляющий символ может быть включен в середину или в конец форматной строки. В языках C, C++ с помощью символа "\" в форматную строку могут быть включены и другие управляющие символы (так называемые Escape-последовательности), список которых приведен в табл. 4.6.
Потоковый вывод
Для начинающих программистов организация потокового вывода числовой информации на стандартное устройство вывода (stdout) представляется более простой:
#include <iostream.h>
int main()
{ int i;
float f;
double d;
..........
cout << i+1 << f << f*d;
Здесь на первых порах не надо заботиться о форматах выводимых результатов. Для каждого типа данных существуют соответствующие системные соглашения. Переход в начало следующей строки здесь осуществляется путем включения в список вывода либо упомянутого выше управляющего символа '\n', либо аналогичного ему признака конца строки endl:
cout << i+1 << f << f*d << endl;
В список выводимых данных могут быть вкраплены и пояснительные подписи:
cout << "x1="<< x1 << "x2=" << x2 << '\n';
В потоковом выводе тоже имеются средства управления форматом вывода числовых результатов. Однако научиться пользоваться ими почти так же сложно, как и овладеть нюансами работы с форматными указателями. Дело в том, что потоки вывода в языке C++ организованы двумя способами – старым и новым. Поэтому в управлении потоком вывода можно встретить различные синтаксические конструкции – традиционные функции (hex – установка режима вывода шестнадцатеричного числа, setw – установка ширины поля вывода, setprecision – установка количества отображаемых цифр и т.п.) и более современные обращения к методам класса (cout.fill(…), cout.width(...)). Некоторые из установленных режимов действуют только на вывод следующего значения, другие сохраняют свое действие до следующей установки. С некоторыми деталями управления форматами числовых данных в потоковом выводе можно познакомиться на примере 4 из следующего параграфа.