Таблица 6.1: Макросы классификации символов
<ctype.h>
Вызов
exit
в конце
vis
не является необходимым для корректной работы программы, но гарантирует тому, кто эту программу вызвал, получение нормального кода ее завершения (обычно нуля). Другой способ возврата кода завершения выполнить в теле функции
main
оператор
return 0
; возвращаемое значение
main
и есть код завершения программы. Если нет явно указанных
return
или
exit
, код завершения не определен.
Для компиляции программы на Си поместите исходный текст в файл, имя которого оканчивается на
.с
, например
vis.с
, оттранслируйте его с помощью
сс
и запустите на выполнение результат, оставляемый компилятором в файле с именем
a.out
('а' — ассемблер):
$ сс vis.с
$ a.out
hello worldctl^g
hello world\007
ctl-d
$
a.out
можно переименовать после первого запуска или сделать это сразу с помощью флага
-о
команды
сс
:
$ сс -о vis vis.с
Результат в vis, а не в a.out
Упражнение 6.1
Мы решили, что символы табуляции не следует делать видимыми, изображая их как
\011
,
→
или
\t
, поскольку главное назначение
vis
— поиск действительно аномальных символов. Можно принять альтернативное решение и недвусмысленно идентифицировать каждый символ в выходном потоке: символы табуляции, неграфические символы, пробелы в конце строки и т.п. Модифицируйте
vis
так, чтобы символы табуляции, обратная дробная черта, "шаг назад", перевод страницы и др. печатались в традиционном, принятом в Си представлении:
\t
,
\\
,
\b
,
\f
и т.д., причем пробелы в конце строки должны быть помечены. Можете сделать это недвусмысленным образом? Сравните ваш вариант с приведенным ниже:
$ sed -n 1
Упражнение 6.2
Модифицируйте
vis
так, чтобы она приводила длинные строки к строкам некоторой разумной длины. Как это согласуется с требованием недвусмысленности результата из предыдущего упражнения?
6.2 Аргументы программы:
vis
версия 2 Когда выполняется программа на Си, функции
main
передаются следующие аргументы из командной строки: счетчик
argc
и массив
argv
, состоящий из указателей символьных строк, содержащих аргументы. По соглашению
argv[0]
это имя самой команды, так что
argc
всегда больше нуля; "полезными" же являются аргументы
argv[1]
...
argv[argc - 1
]. Вспомните, что переключение входного или выходного потоков с помощью
<
и
>
осуществляется в
shell
, а не отдельными программами, поэтому такое переключение не влияет на число аргументов, видимых программой.
Для иллюстрации работы с аргументами модифицируем
vis
, добавив флаг:
vis -s
удаляет любые непечатаемые символы вместо того, чтобы выделять их. Такое удаление удобно для "чистки" файлов из других систем, например тех, которые используют для завершения строки CRLF (символы возврата каретки и перевода строки) вместо одного символа перевода строки.
/* vis: make funny characters visible (version 2) */
#include <stdio.h>
#include <ctype.h>
main(argc, argv)
int argc;
char *argv[];
{
int c, strip = 0;
if (argc > 1 && strcmp(argv[1], "-s") == 0)
strip = 1;
while ((c = getchar()) != EOF)
if (isascii(c) &&
(isprint(с) || c=='\n' || c=='\t' || c==' '))
putchar(c);
else if (!strip)
printf("\\%03o", c);
exit(0);
}
Здесь
argv
— указатель массива, элементы которого служат указателями массивов символов; каждый такой массив заканчивается символом ASCII NUL (
'\0'
), поэтому массив можно считать строкой. Эта версия
vis
начинает свою работу с того, что проверяет, есть ли аргумент и является ли он
-s
. (Неверные аргументы игнорируются.) Функция
strcmp(3)
сравнивает две строки, возвращая нуль, если они одинаковы.
В табл. 6.2 перечислены некоторые средства работы со строками и ряд полезных функций, одна из которых
strcmp
. Как правило, лучше воспользоваться этими стандартными функциями, чем писать собственные, так как они отлажены и зачастую выполняются быстрее, чем написанные вами, поскольку были оптимизированы для конкретных машин (нередко благодаря использованию Ассемблера).
strcat(s,t)
| Добавляет строку t к строке s ; возвращает s
|
strncat(s,t,n)
| Добавляет не более n символов t к s
|
strcpy(s,t)
| Копирует t в s ; возвращает s
|
strncpy(s,t,n)
| Копирует точно n символов; при необходимости добавляет NULL
|
strcmp(s,t)
| Сравнивает s и t , возвращает <0, 0, >0 при <, ==, > |
strncmp(s,t,n)
| Сравнивает не более n символов |
strlen(s)
| Возвращает длину s
|
strchr(s,c)
| Возвращает указатель на первый символ с в s и NULL , если с отсутствует |
strrchr(s,c)
| Возвращает указатель на последний с в s и NULL , если с отсутствует. |
atoi(s)
| Возвращает целое значение s
|
atof(s)
| Возвращает "плавающее" значение s ; необходимо описание double atof()
|
malloc(n)
| Возвращает указатель на область памяти в n байт и NULL , если это невозможно |
calloc(n,m)
| Возвращает указатель на n*m обнуленных байтов и NULL , если это невозможно; malloc и calloc возвращают значение типа char*
|
free(p)
| Освобождает память, выделенную malloc и calloc
|