Смекни!
smekni.com

Методические указания к выполнению контрольных работ по дисциплине "Основы программирования" (стр. 38 из 40)

prog>outfile

приведет к записи стандартного вывода в файл outfile, а не на терминал. Можно также использовать поточный механизм. Строка:

prog | anotherprog

помещает стандартный вывод prog в стандартный ввод anotherprog. И опять prog не будет осведомлена об изменении направления.

Вывод, осуществляемый функцией printf, также поступает в стандартный вывод, и обращения к putchar и printf могут перемежаться.

Пример 9-1. Поразительное количество программ читает только из одного входного потока и пишет только в один выходной поток; для таких программ ввод и вывод с помощью функций getchar, putchar и printf может оказаться вполне адекватным и для начала определенно достаточным. Это особенно справедливо тогда, когда имеется возможность указания файлов для ввода и вывода и поточный механизм для связи вывода одной программы с вводом другой. Рассмотрим, например, программу lower, которая преобразует прописные буквы из своего ввода в строчные:

// Преобразование прописных букв в строчные

#include <stdio.h>

main()

{

int c;

while ((c = getchar()) != EOF)

putchar(isupper(c) ? tolower(c) : c);

}

«Функции» isupper и tolower на самом деле являются макросами, определенными в stdio.h . Макрос isupper проверяет, является ли его аргумент буквой из верхнего регистра, и возвращает ненулевое значение, если это так, и нуль в противном случае. Макрос tolower преобразует букву из верхнего регистра в ту же букву нижнего регистра. Независимо от того, как эти функции реализованы на конкретной машине, их внешнее поведение совершенно одинаково, так что использующие их программы избавлены от знания символьного набора.

Если требуется преобразовать несколько файлов, то можно собрать эти файлы с помощью программы, подобной утилите cat системы Unix,

cat file1 file2 ... | lower>output

и избежать тем самым вопроса о том, как обратиться к этим файлам из программы (программа cat приводится позже в этой главе).

Кроме того отметим, что в стандартной библиотеке ввода/вывода «функции» getchar и putchar на самом деле могут быть макросами. Это позволяет избежать накладных расходов на обращение к функции для обработки каждого символа.

9.3. Форматный вывод: функция printf

Две функции: printf для вывода и scanf для ввода (следующий раздел) позволяют преобразовывать численные величины в символьное представлEние и обратно. Они также позволяют генерировать и интерпретировать форматные строки. Мы уже всюду в предыдущих главах неформально использовали функцию printf; здесь приводится более полное и точное описание. Функция:

printf(control, arg1, arg2, ...)

преобразует, определяет формат и печатает свои аргументы в стандартный вывод под управлением строки control. Управляющая строка содержит два типа объектов: обычные символы, которые просто копируются в выходной поток, и спецификации преобразований, каждая из которых вызывает преобразование и печать очередного аргумента printf.

Каждая спецификация преобразования начинается с символа % и заканчивается символом преобразования. Между % и символом преобразования могут находиться:

· знак минус, который указывает о выравнивании преобразованного аргумента по левому краю его поля;

· строка цифр, задающая минимальную ширину поля. Преобразованное число будет напечатано в поле по крайней мере этой ширины, а если необходимо, то и в более широком. Если преобразованный аргумент имеет меньше символов, чем указанная ширина поля, то он будет дополнен слева (или справа, если было указано выравнивание по левому краю) заполняющими символами до этой ширины. Заполняющим символом обычно является пробел, а если ширина поля указывается с лидирующим нулем, то этим символом будет нуль (лидирующий нуль в данном случае не означает восьмеричной ширины поля);

· точка, которая отделяет ширину поля от следующей строки цифр;

· строка цифр (точность), которая указывает максимальное число символов строки, которые должны быть напечатаны, или число печатаемых справа от десятичной точки цифр для переменных типа float или double;

· модификатор длины l, который указывает, что соответствующий элемент данных имеет тип long, а не int.

Ниже приводятся символы преобразования и их смысл:

d – аргумент преобразуется к десятичному виду;

o – аргумент преобразуется в беззнаковую восьмеричную форму (без лидирующего нуля);

x – аргумент преобразуется в беззнаковую шестнадцатеричную форму (без лидирующих 0x);

u – аргумент преобразуется в беззнаковую десятичную форму;

c – аргумент рассматривается как отдельный символ;

s – аргумент является строкой: символы строки печатаются до тех пор, пока не будет достигнут нулевой символ или не будет напечатано количество символов, указанное в спецификации точности;

e – аргумент, рассматриваемый как переменная типа float или double, преобразуется в десятичную форму в виде:

[-]m.nnnnnn e[+-]xx ,

где длина строки из n определяется указанной точностью. Точность по умолчанию равна 6.

f – аргумент, рассматриваемый как переменная типа float или double, преобразуется в десятичную форму в виде:

[-]mmm.nnnnn ,

где длина строки из n определяется указанной точностью. Точность по умолчанию равна 6. отметим, что эта точность не определяет количество печатаемых в формате F значащих цифр.

g – используется или формат %e или %f, какой короче; незначащие нули не печатаются.

Если идущий за % символ не является символом преобразования, то печатается сам этот символ; следовательно, символ % можно напечатать, указав %%.

Пример 9-2. Большинство из форматных преобразований очевидно и было проиллюстрировано в предыдущих главах. Единственным исключением является то, как точность взаимодействует со строками. Следующий пример демонстрирует влияние задания различных спецификаций на печать

"Hello, World" (12 символов, включая 1 пробел).

Мы поместили двоеточия вокруг каждого поля для того, чтобы вы могли видеть его протяженность:

:%s: :Hello, World:

:%10s: :Hello, World:

:%20s: : Hello, World:

:%-20s: :Hello, World :

:%.10s: :Hello, Wor:

:%15.10s: : Hello, Wor:

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

Упражнение 8-1. Напишите программу, которая будет печатать разумным образом произвольный ввод. Как минимум она должна печатать неграфические символы в восьмеричном или шестнадцатеричном виде (в соответствии с принятыми у вас обычаями) и складывать длинные строки.

9.4. Форматный ввод: функция scanf

Осуществляющая ввод функция scanf является аналогом printf и позволяет проводить в обратном направлении многие из тех же самых преобразований. Функция:

scanf(control, arg1, arg2, ...)

читает символы из стандартного ввода, интерпретирует их в соответствии с форматом, указанном в аргументе control, и помещает результаты в остальные аргументы. Управляющий аргумент описывается ниже; другие аргументы, каждый из которых должен быть указателем, определяют, куда следует поместить соответствующим образом преобразованный ввод.

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

· пробелы, табуляции или символы новой строки («символы пустых промежутков»), которые игнорируются;

· обычные символы (не %), которые предполагаются совпадающими со следующими отличными от символов пустых промежутков символами входного потока;

· спецификации преобразования, каждая из которых начинается с символа % и завершается символом-спецификатором типа преобразования. Между этими двумя символами могут быть (в том порядке, в котором они здесь указаны): необязательный символ подавления присваивания *; необязательное число, задающее максимальную ширину поля; буква h или l , указывающая на размер получаемого значения, и символ преобразования (o, d, x).

Спецификация преобразования управляет преобразованием следующего поля ввода. Нормально результат помещается в переменную, которая указывается соответствующим аргументом. Если, однако, с помощью символа * указано подавление присваивания, то это поле ввода просто пропускается и никакого присваивания не производится. Поле ввода определяется как строка символов, которые отличны от символов простых промежутков; оно продолжается либо до следующего символа пустого промежутка, либо пока не будет исчерпана ширина поля, если она указана. Отсюда следует, что при поиске нужного ей ввода, функция scanf будет пересекать границы строк, поскольку символ новой строки входит в число пустых промежутков.

Символ преобразования определяет интерпретацию поля ввода; согласно требованиям основанной на вызове по значению семантики языка «С» соответствующий аргумент должен быть указателем. Допускаются следующие символы преобразования:

d - на вводе ожидается десятичное целое; соответствующий аргумент должен быть указателем на целое;

o - на вводе ожидается восьмеричное целое (с лидирующим нулем или без него); соответствующий аргумент должен быть указателем на целое;

x - на вводе ожидается шестнадцатеричное целое (с лидирующими 0x или без них); соответствующий аргумент должен быть указателем на целое.

h - на вводе ожидается целое типа short; соответсвующий аргумент должен быть указателем на целое типа short;

c - ожидается отдельный символ; соответствующий аргумент должен быть указателем на символы; следующий вводимый символ помещается в указанное место. Обычный пропуск символов пустых промежутков в этом случае подавляется; для чтения следующего символа, который не является символом пустого промежутка, пользуйтесь спецификацией преобразования %1s;

s - ожидается символьная строка; соответствующий аргумент должен быть указателем символов, который указывает на массив символов, который достаточно велик для принятия строки и добавляемого в конце символа &bsol;0.