Керниган и Ритчи - Язык программирования Си (793773), страница 39
Текст из файла (страница 39)
Это константы, а непеременные, следовательно, им нельзя ничего присваивать.Функцияint fclose(FILE *fp)— обратная по отношению к fopen; она разрывает связь между файловым указателем и внешним именем(которая раньше была установлена с помощью fopen), освобождая тем самым этот указатель для другихфайлов. Так как в большинстве операционных систем количество одновременно открытых одной программойфайлов ограничено, то файловые указатели, если они больше не нужны, лучше освобождать, как это иделается в программе cat. Есть еще одна причина применить fclose к файлу вывода, это необходимость"опорожнить" буфер, в котором putc накопила предназначенные для вывода данные.
При нормальномзавершении работы программы для каждого открытого файла fclose вызывается автоматически. (Выможете закрыть stdin и stdout, если они вам не нужны. Воспользовавшись библиотечной функциейfreopen, их можно восстановить.)7.6. Управление ошибками (stderr и exit)Обработку ошибок в cat нельзя признать идеальной. Беда в том, что если файл по какой-либо причиненедоступен, сообщение об этом мы получим по окончании конкатенируемого вывода.
Это нас устроило бы,если бы вывод отправлялся только на экран, а не в файл или по конвейеру другой программе.Чтобы лучше справиться с этой проблемой, программе помимо стандартного вывода stdout придается ещеодин выходной поток, называемый stderr. Вывод в stderr обычно отправляется на экран, даже есливывод stdout перенаправлен в другое место.Перепишем cat так, чтобы сообщения об ошибках отправлялись в stderr.#include <stdio.h>/* cat: конкатенация файлов, версия 2 */main(int argc, char *argv[]){FILE *fp;void filecopy(FILE *, FILE *);char *prog = argv[0]; /* имя программы */if (argc ==1) /* нет аргументов; копируется станд. ввод */filecopy(stdin, stdout);elsewhile (--argc > 0)if ((fp = fopen(*++argv, "r")) == NULL) {fprintf (stderr, "%s: не могу открыть файл %s\n",prog, *argv);exit(t);} else {filecopy(fp, stdout);fclose(fp);}if (ferror(stdout)) {fprintf (stderr, "%s: ошибка записи в stdout\n", prog);exit(2);}exit(0);}Программа сигнализирует об ошибках двумя способами.
Первый — сообщение об ошибке с помощьюfprintf посылается в stderr с тем, чтобы оно попало на экран, а не оказалось на конвейере или в другомфайле вывода. Имя программы, хранящееся в argv[0], мы включили в сообщение, чтобы в случаях, когдаданная программа работает совместно с другими, был ясен источник ошибки.Второй способ указать на ошибку — обратиться к библиотечной функции exit, завершающей работупрограммы.
Аргумент функции exit доступен некоторому процессу, вызвавшему данный процесс. Аследовательно, успешное или ошибочное завершение программы можно проконтролировать с помощьюнекоей программы, которая рассматривает эту программу в качестве подчиненного процесса. По общейдоговоренности возврат нуля сигнализирует о том, что работа прошла нормально, в то время как ненулевыезначения обычно говорят об ошибках. Чтобы опорожнить буфера, накопившие информацию для всехоткрытых файлов вывода, функция exit вызывает fclose.Инструкция return выр главной программы main эквивалентна обращению к функции exit(выр).Последний вариант (с помощью exit) имеет то преимущество, что он пригоден для выхода и из другихфункций, и, кроме того, слово exit легко обнаружить с помощью программы контекстного поиска, похожейна ту, которую мы рассматривали в главе 5.Функция ferror выдает ненулевое значение, если в файле fp была обнаружена ошибка.int ferror(FILE *fp)Хотя при выводе редко возникают ошибки, все же они встречаются (например, оказался переполненнымдиск); поэтому в программах широкого пользования они должны тщательно контролироваться.Функция feof(FILE *) аналогична функции ferror; она возвращает ненулевое значение, если встретилсяконец указанного в аргументе файла.int feof(FILE *fp)В наших небольших иллюстративных программах мы не заботились о выдаче статуса выхода, т.
е. выдаченекоторого числа, характеризующего состояние программы в момент завершения: работа закончиласьнормально или прервана из-за ошибки? Если работа прервана в результате ошибки, то какой? Любаясерьезная программа должна выдавать статус выхода.7.7. Ввод-вывод строкВ стандартной библиотеке имеется программа ввода fgets, аналогичная программе getline, которой мыпользовались в предыдущих главах.char *fgets(char *line, int maxline, FILE *fp)Функция fgets читает следующую строку ввода (включая и символ новой строки) из файла fp в массивсимволов line, причем она может прочитать не более MAXLINE-1 символов. Переписанная строкадополняется символом '\0'.
Обычно fgets возвращает line, а по исчерпании файла или в случае ошибки— NULL. (Наша getline возвращала длину строки, которой мы потом пользовались, и нуль в случае концафайла.)Функция вывода fputs пишет строку (которая может и не заканчиваться символом новой строки) в файл.int fputs(char *line, FILE *fp)Эта функция возвращает EOF, если возникла ошибка, и неотрицательное значение в противном случае.Библиотечные функции gets и puts подобны функциям fgets и fputs. Отличаются они тем, чтооперируют только стандартными файлами stdin и stdout, и кроме того, gets выбрасывает последнийсимвол '\n', a puts его добавляет.Чтобы показать, что ничего особенного в функциях вроде fgets и fputs нет, мы приводим их здесь в томвиде, в каком они существуют в стандартной библиотеке на нашей системе./* fgets: получает не более n символов из iop */char *fgets(char *s, int n, FILE *iop){register int c;register char *cs;cs = s;while (--n > 0 && (c = getc(iop)) != EOF)if ((*cs++ = c) == '\n' )break;*cs = '\0' ;return (c == EOF && cs == s) ? NULL : s;}/* fputs: посылает строку s в файл iop */int fputs(char *s, FILE *iop){int c;while (c = *s++)putc(c, iop);return ferror(iop) ? EOF : 0;}Стандарт определяет, что функция ferror возвращает в случае ошибки ненулевое значение; fputs в случаеошибки возвращает EOF, в противном случае — неотрицательное значение.С помощью fgets легко реализовать нашу функцию getline:/* getline: читает строку, возвращает ее длину */int getline(char *line, int max){if (fgets(line, max, stdin) == NULL)return 0;elsereturn strlen(line);}Упражнение 7.6.
Напишите программу, сравнивающую два файла и печатающую первую строку, в которойони различаются.Упражнение 7.7. Модифицируйте программу поиска по образцу из главы 5 таким образом, чтобы она бралатекст из множества именованных файлов, а если имен файлов в аргументах нет, то из стандартного ввода.Будет ли печататься имя файла, в котором найдена подходящая строка?Упражнение 7.8. Напишите программу, печатающую несколько файлов.
Каждый файл должен начинаться сновой страницы, предваряться заголовком и иметь свою нумерацию страниц.7.8. Другие библиотечные функцииВ стандартной библиотеке представлен широкий спектр различных функций. Настоящий параграф содержиткраткий обзор наиболее полезных из них. Более подробно эти и другие функции описаны в приложении В.7.8.1. Операции со строкамиМы уже упоминали функции strlen, strcpy, strcat и strcmp, описание которых даны в <string.h>.Далее, до конца пункта, предполагается, что s и t имеют тип char *, c и n — тип int.strcat(s, t)— приписывает t в конец s.strncat(s, t, n)— приписывает n символов из t в конец s.strcmp(s, t)— возвращает отрицательное число, нуль или положительное число для s < t, s== t или s > t соответственно.strncmp(s, t, n)— делает то же, что и strcmp, но количество сравниваемых символов не можетпревышать n.strcpy(s, t)— копирует t в s.strncpy(s, t, n)— копирует не более n символов из t в s.strlen(s)— возвращает длину s.strchr(s, с)— возвращает указатель на первое появление символа c в s или, если c нет в s,NULL.strrchr(s, с)— возвращает указатель на последнее появление символа c в s или, если c нет вs, NULL.7.8.2.
Анализ класса символов и преобразование символовНесколько функций из библиотеки <ctype.h> выполняют проверки и преобразование символов. Далее, доконца пункта, переменная с — это переменная типа int, которая может быть представлена значениемunsigned char или EOF. Все эти функции возвращают значения типа int.isalpha(c)— не нуль, если c — буква; 0 в противном случае.isupper(c)— не нуль, если c — буква верхнего регистра; 0 в противном случае.islower(c)— не нуль, если c — буква нижнего регистра; 0 в противном случае.isdigit(c)— не нуль, если c — цифра; 0 в противном случае.isalnum(c)— не нуль, если или isalpha(c), или isdigit(c) истинны; 0 в противном случае.isspace(c)— не нуль, если c — символ пробела, табуляции, новой строки, возврата каретки,перевода страницы, вертикальной табуляции.toupper(с)— возвращает c, приведенную к верхнему регистру.tolower(с)— возвращает c, приведенную к нижнему регистру.7.8.3.














