Литмир - Электронная Библиотека
Содержание  
A
A

6.1 Стандартные входной и выходной потоки: программа

vis

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

Проиллюстрируем изложенное с помощью программы

vis
, которая копирует свой стандартный входной поток в стандартный выходной, изображая при этом все непечатаемые символы в виде
\nnn
, где
nnn
— восьмеричное значение символа.
Vis
полезна для обнаружения "посторонних" или нежелательных символов, которые могут попасть в файлы. Например,
vis
будет печатать каждый символ "шаг назад" как \010, что является его восьмеричным значением:

$ cat x abc

$ vis < x

abc\010\010\010 ___

$

Чтобы просмотреть несколько файлов с помощью этой элементарной версии

vis
, вы можете использовать
cat
для сбора файлов

$ cat файл1 файл2 ... | vis

...

$ cat файл1 файл2 ... | vis | grep '\\'

...

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

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

sed
, поскольку команда
'1'
выдает на экран непечатаемые символы в наглядном виде:

$ sed -n 1 x

abc←←←___

$

Результат выполнения программы

sed
, вероятно, вам покажется яснее, чем результат выполнения
vis
. Но применение
sed
к нетекстовым файлам бессмысленно:

$ sed -n 1 /usr/you/bin

$
Ничего в ответ!

(Так получилось на PDP-11; в одной из систем для VAX

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

Простейшие функции ввода и вывода

getchar
и
putchar
. При каждом вызове
getchar
появляется очередной символ из стандартного входного потока, которому может быть поставлен в соответствие файл, конвейер или терминал (последнее принимается по умолчанию). Программа "не знает", что конкретно он собой представляет. Аналогично
putchar(c)
помещает символ в стандартный выходной поток, который по умолчанию также связан с терминалом.

Функция

printf(3)
выполняет форматное преобразование при выводе. Вызовы
printf
и
putchar
могут следовать в любом порядке; выходной поток отразит порядок этих вызовов. Для форматного преобразования входного потока предусмотрена функция
scanf(3)
; она читает входной поток и разбивает его, как требуется, на строки, числа и т.п. Вызовы
scanf
и
getchar
также могут чередоваться.

Приведем первую версию

vis
:

/* vis: make funny characters visible (version 1) */

#include <stdio.h>

#include <ctype.h>

main() {

 int c;

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

  if (isascii(c) &&

   (isprint(с) || c=='\n' || c=='\t' || c==' '))

   putchar(c);

  else

   printf("\\%03o", c);

 exit(0);

}

Getchar
возвращает из входного потока очередной байт или значение EOF, когда встречает конец файла (или ошибку). Между прочим, EOF не является байтом из файла; вспомните: во второй главе объяснялось, что такое "конец файла". Значение EOF отличается от значения любого байта, поэтому его трудно спутать с реальными данными; переменная с описана как
int
(целая), а; не как
char
(символьная), так что она может хранить значение EOF. Строка

#include <stdio.h>

должна находиться в начале каждого исходного файла. Это заставляет компилятор Си читать файл макроопределений (

/usr/include/stdio.h
), в котором специфицированы стандартные функции и имена, в том числе и
EOF
. Мы будем использовать
<stdio.h>
как краткую запись полного имени файла.

Файл

<ctype.h>
— еще один файл макроопределений в
/usr/include
, который задает машинно-независимые макрокоманды (макросы) для классификации символов. Чтобы выяснить, принадлежит ли входной символ набору ASCII (т.е. его значение меньше 0200) и печатается ли он, мы использовали здесь
isascii
и
isprint
. Остальные макросы перечислены в табл. 6.1. Отметим, что
<ctype.h>
определяет символы "перевод строки", "табуляция" и пробел как непечатаемые.

isalpha(c)
Буква принадлежит алфавиту:
a-z A-Z
isupper(c)
Прописная буква:
A-Z
islower(с)
Строчная буква:
a-z
isdigit(c)
Цифра:
0-9
isxdigit(c)
Шестнадцатеричная цифра:
0-9 a-f A-F
isalnum(c)
Буква или цифра
isspace(c)
Пробел, символ табуляции, символ перевода строки, символ вертикальной табуляции, символ перевода страницы, символ возврата
ispunct(c)
Не буквенно-цифровой символ, не управляющий, не пробел
isprint(c)
Печатаемый: любой графический символ
iscntrl(c)
Управляющий символ:
0 <= с < 040 || с == 0177
isascii(c)
Символ ASCII:
0 <= с <= 0177
75
{"b":"248117","o":1}