Далее, нужен способ читать или писать файл после того, как он открыт. Есть несколько способов, из которых использование getc
и putc
самый простой. Функция getc
выбирает из файла очередной символ:
с = getc(fp)
помещает в с
следующий символ из файла, на который указывает fp
. Эта функция возвращает EOF
по достижении конца файла. Функция putc
аналогична getc
:
putc(c, fp)
помещает символ с
в файл fp
и возвращает с
. Функции getc
и putc
возвращают EOF
в случае ошибки.
Когда программа начинает выполняться, уже открыты три файла и имеются их указатели. Это стандартные потоки: входной, выходной и поток диагностики; соответствующие указатели называются stdin
, stdout
и stderr
. Указатели на файлы описаны в > и могут использоваться там, где может быть объект типа FILE*
. Они являются не переменными, а константами, так что им нельзя присвоить значения. Вызов getchar()
есть getc(stdin)
, a putchar(c)
есть putc(c, stdout)
. На самом деле все эти четыре "функции" определены в как макрокоманды. Они выполняются быстрее обычных вызовов функций ввиду отсутствия накладных расходов по вызову функции для каждого символа (см. табл. 6.3 с некоторыми другими определениями из ).
stdin |
Стандартный входной поток |
stdout |
Стандартный выходной поток |
stderr |
Стандартный поток диагностики |
EOF |
Конец файла; обычно -1 |
NULL |
Несуществующий указатель; обычно 0 |
FILE |
Используется для описания указателей на файлы |
BUFSIZ |
Обычно размер буфера ввода вывода (часто 512 или 1024) |
getc(fp) |
Возвращает один символ из потока fp |
getchar() |
getc(stdin) |
putc(c,fp) |
Помещает символ с в поток fp |
putchar(c) |
putс(с,stdout) |
feof(fp) |
Не нуль, если достигнут конец файла для потока fp |
ferror(fp) |
Не нуль, если в потоке fp есть ошибка |
fileno(fp) |
Дескриптор файла для потока fp (см. гл. 7) |
Таблица 6.3: Некоторые определения из
Теперь вернемся снова к нашей теме и напишем третью версию vis
. Если есть аргументы командной строки, они обрабатываются в порядке очередности, если же аргументов нет, используется стандартный входной поток.
/* vis: make funny characters visible (version 3) */
#include
#include
int strip = 0; /* 1 => discard special characters */
main(argc, argv)
int argc;
char *argv[];
{
int i;
FILE *fp;
while (argc > 1 && argv[1][0] == '-') {
switch (argv[1][1]) {
case 's': /* -s: strip funny chars */
strip = 1;
break;
default:
fprintf(stderr, "%s: unknown arg %s\n",
argv[0], argv[1]);
exit(1);
}
argc--;
argv++;
}
if (argc == 1)
vis(stdin);
else
for (i = 1; i < argc; i++)
if ((fp=fopen(argv[i], "r")) == NULL) {
fprintf(stderr, "%s: can't open %s\n",
argv[0], argv[i]);
exit(1);
} else {
vis(fp);
fclose(fp);
}
exit(0);
}
В программе принято соглашение, по которому флаги стоят в начале списка аргументов. После обработки каждого флага argv
и argc
модифицируются так, что остальная часть программы не зависит от присутствия этого флага. Даже если vis
распознает единственный флаг, мы написали программу в виде цикла, чтобы продемонстрировать единый способ обработки аргументов. В гл. 1 отмечалось, что программы UNIX обрабатывают флаги в произвольном порядке. Как одну из причин (помимо склонности к анархии) здесь можно назвать очевидную легкость написания программы разбора аргументов при любой модификации. Включение функции getopt(3)
в некоторые системы является попыткой рационально объяснить ситуацию; вы можете ее исследовать, прежде чем писать собственную.
Процедура vis
выводит на печать единственный файл:
vis(fp) /* make chars visible in FILE *fp */
FILE *fp;
{
int c;
while ((с = getc(fp)) != EOF)
if (isascii(c) &&
(isprint(с) || c=='\n' || c=='\t' || c==' '))
putchar(c);
else if (!strip)
printf("\\%03o", c);
}
Функция fprintf
идентична printf
, за исключением аргумента указателя, специфицирующего файл, в который нужно писать.
Функция fclose
разрывает связь между указателем и внешним именем файла, установленную с помощью fopen
, освобождая указатель для другого файла. Так как существует ограничение (около 20) на число файлов, которые одновременно могут быть открыты в программе, лучше всего закрывать уже не требующиеся вам файлы. Обычно выходной поток, выдаваемый любой стандартной библиотечной функцией, подобной printf
, putc
и т.д., для большей эффективности буферизуется так, чтобы его можно было писать большими фрагментами. (Исключение составляет выходной поток терминала, который, как правило, пишется по мере своего формирования или при печати символа перевода строки.) Применение fclose
к выходному файлу инициирует выдачу последней буферизованной порции, fclose
также вызывается автоматически для каждого открытого файла, когда программа выполняет exit
или возвращается из main
.
Читать дальше
Конец ознакомительного отрывка
Купить книгу