Средства
Мы здесь не будем пытаться описать всю библиотеку
Каждый
#include <stdio.h>
в файле stdio.h определяются некоторые макросы и /usr/include ).
Кроме того, при загрузке
cc исходные файлы и т.д. -ls
где -ls указывает на загрузку из
Самый простой механизм getchar. getchar()
при каждом к ней обращении возвращает
следующий <: если некоторая prog использует getchar то командная строка
prog<infile
приведет к тому, что prog будет читать
из файла infile, а не с prog не замечает
изменения; в частности строка" <infile " не включается
в командную строку argv. Переключение pipe )
механизма; командная строка
otherprog | prog
прогоняет две otherprog и prog,
и организует так, что стандартным prog служит
стандартный otherprog.
getchar возвращает значение EOF,
когда она попадает на EOF равной -1
(посредством #define в файле stdio.h ), но проверки
следует писать в терминах EOF, а не -1, чтобы избежать
зависимости от конкретного значения.
putchar(c),
помещающей символ 'с' в "стандартный > если prog использует putchar, то командная строка
prog>outfile
приведет к записи стандартного outfile,
а не на
prog | anotherprog
помещает стандартный prog в стандартный anotherprog. И опять prog не
будет осведомлена об изменении направления.
printf,
также поступает в стандартный putchar
и printf могут перемежаться.
Поразительное количество getchar, putchar и printf может оказаться вполне адекватным и
для начала определенно достаточным. Это особенно справедливо тогда, когда
имеется возможность указания файлов для lower, которая преобразует прописные
буквы из своего
#include <stdio.h>
main() /* convert input to lower case */
{
int c;
while ((c = getchar()) != EOF)
putchar(isupper(c) ? tolower(c) : c);
}
" isupper и tolower на
самом деле являются макросами, stdio.h. Макрос isupper проверяет, является ли его tolower преобразует букву из верхнего
регистра в ту же букву нижнего регистра. Независимо от того, как эти
Если требуется преобразовать несколько файлов, то можно собрать эти файлы
с помощью cat
системы
cat file1 file2 ... | lower>output
и избежать тем самым вопроса о том, как обратиться к этим файлам из cat приводится позже в этой лекции).
Кроме того отметим, что в getchar и putchar
на самом деле могут быть макросами. Это позволяет избежать накладных
расходов на
Две printf для scanf
для printf ; здесь
приводится более полное и точное
printf(control, arg1, arg2, ...)
преобразует, определяет формат и печатает свои control. Управляющая строка содержит два printf.
Каждая %
и заканчивается символом преобразования. Между % и символом
преобразования могут находиться:
float или double.l, который указывает,
что соответствующий элемент long,
а не int.Ниже приводятся символы преобразования и их смысл:
d - o - x - 0x ).u - c - s - e - float или double, преобразуется в десятичную форму в виде [-]m.nnnnnne[+-]xx, где длина строки из n определяется
указанной точностью. Точность по умолчанию равна 6.f - float или double, преобразуется в десятичную форму в виде [-]mmm .nnnnn, где длина строки из n определяется указанной
точностью. Точность по умолчанию равна 6. Отметим, что эта
точность не определяет количество печатаемых в формате f
значащих цифр.g - Используется или формат %e или %f,
какой короче; незначащие нули не печатаются. Если идущий за % символ не является символом преобразования, то
печатается сам этот символ; следовательно, символ % можно
напечатать, указав %%.Большинство из форматных преобразований очевидно и было проиллюстрировано
в предыдущих лекциях. Единственным исключением является то, как точность
взаимодействует со строками. Следующая таблица демонстрирует влияние задания
различных hello, world " (12 символов). Мы поместили
двоеточия вокруг каждого поля для того, чтобы вы могли видеть его протяженность.
:%10s: :hello, world: :%10-s: :hello, world: :%20s: : hello, world: :%-20s: :hello, world : :%20.10s: : hello, wor: :%-20.10s: :hello, wor : :%.10s: :hello, wor:
Предостережение: printf использует свой первый
Упражнение 7-1
Напишите
Осуществляющая scanf является аналогом printf и позволяет проводить в обратном направлении многие
из тех же самых преобразований.
scanf(control, arg1, arg2, ...)
читает символы из стандартного control, и помещает результаты в остальные
Управляющая строка обычно содержит
% ), которые предполагаются
совпадающими со следующими отличными от символов пустых промежутков
символами входного потока.%,
необязательного символа подавления присваивания *,
необязательного числа, задающего максимальную ширину поля и символа
преобразования.* указано
подавление присваивания, то это поле scanf будет пересекать границы строк,
поскольку
Символ преобразования определяет интерпретацию поля
d - на o - На x - На 0x или без них); соответствующий h - На short ;
соответствующий short.c - Ожидается отдельный символ; соответствующий %1s.s - Ожидается \0.f - Ожидается число с плавающей точкой; соответствующий float.Е - символ преобразования e
является синонимом для f. Формат float включает необязательный знак,
строку цифр, возможно содержащую десятичную точку и
необязательное поле экспоненты, состоящее из буквы e, за которой
следует целое, возможно имеющее знак.Перед символами преобразования d, o и x может стоять l,
которая означает , что в long, а
не int. Аналогично, буква l может
стоять перед символами преобразования e или f, говоря о том, что в double, а не float.
Например, обращение
int i; float x; char name[50]; scanf("%d %f %s", i, x, name);
со строкой на
25 54.32e-1 thompson
приводит к присваиванию i значения 25, x - значения 5.432 и name - строки
" thompson ", надлежащим образом законченной символом \0. эти три поля
int i;
float x;
char name[50];
scanf("%2d %f %*d %2s", i, x, name);
с
56789 0123 45a72
присвоит i значение 56, x - 789.0, пропустит 0123
и поместит в name строку "45".
При следующем обращении к любой a. В этих двух примерах name является .
В качестве другого примера перепишем теперь элементарный калькулятор из
лекции №4, используя для преобразования scanf:
#include <stdio.h>
main() /* rudimentary desk calculator */
{
double sum, v;
sum =0;
while (scanf("%lf", v) !=EOF)
printf("\t%.2f\n", sum += v);
}
выполнение scanf заканчивается
либо тогда, когда она исчерпывает свою
управляющую строку, либо когда некоторый элемент EOF ; подчеркнем, что это значение
отлично от 0, что следующий scanf поиск возобновляется непосредственно за
последним введенным символом.
Заключительное предостережение: scanf должны быть
scanf("%d", n);
вместо
scanf("%d", n);
От scanf и printf
происходят sscanf и sprintf, которые
осуществляют аналогичные преобразования, но оперируют со строкой, а не с файлом.
sprintf(string, control, arg1, arg2, ...) sscanf(string, control, arg1, arg2, ...)
Как и раньше , sprintf преобразует свои arg1, arg2 и т.д. В соответствии с форматом, указанным
в control, но помещает результаты в string, а
не в стандартный string должна быть
достаточно велика, чтобы принять результат. Например, если name - это n - целое, то
sprintf(name, "temp%d", n);
создает в name строку вида tempnnn,
где nnn - значение n.
sscanf выполняет обратные
преобразования - она просматривает строку string
в соответствии с форматом в control и помещает результирующие значения в arg1, arg2 и т.д. Эти
sscanf(name, "temp%d", n);
n получает значение строки цифр,
следующих за temp в name.
Упражнение 7-2
Перепишите настольный калькулятор из лекции №4, используя для scanf и/или sscanf.
Все до сих пор написанные
Следующим шагом в вопросе cat, которая объединяет набор из нескольких
именованных файлов в стандартный cat
используется для
cat x.c,y.c
печатает содержимое файлов x.c и y.c
в стандартный
Вопрос состоит в том, как организовать чтение из именованных файлов,
т.е., как связать внешние имена, которыми мыслит пользователь, с фактически
читающими
Эти правила просты. Прежде чем можно считывать из некоторого файла или
записывать в него, этот файл должен быть открыт с помощью fopen из fopen берет внешнее имя (подобное x.c
или y.c ), проводит некоторые обслуживающие действия и переговоры с
Это внутреннее имя, называемое " stdio.h, содержится file. Единственное необходимое для
file *fopen(), *fp;
Здесь говорится, что fp является file и fopen возвращает file. Oбратите внимание, что file
является именем int, а
не ярлыку typedef.
(Подробности того, как все это работает на системе
Фактическое fopen в
fp=fopen(name,mode);
Первым fopen является "имя" файла, которое задается в
виде mode("режим") также является r "), запись (" w ")
и добавление (" a ").
Если вы откроете файл, который еще не существует, для записи или добавления, то такой файл будет создан (если это возможно).
Открытие существующего файла на запись приводит к отбрасыванию его старого
содержимого. Попытка чтения несуществующего файла является ошибкой. Ошибки
могут быть обусловлены и другими причинами (например, попыткой
чтения из файла, не имея на то разрешения). При наличии какой-либо
ошибки null (которое для
удобства также определяется в файле stdio.h ).
Другой необходимой вещью является способ чтения или записи, если файл
уже открыт. Здесь имеется несколько возможностей, из которых getc
и putc являются простейшими. getc
возвращает следующий символ из файла; ей
необходим
c=getc(fp)
помещает в "C" следующий символ из файла, указанного посредством fp, и EOF, если достигнут
putc, являющаяся getc,
putc(c,fp)
помещает символ " c " в файл fp и возвращает " c ".
Подобно getchar и putchar, getc и putc
могут быть макросами, а не
При запуске stdin, stdout и stderr. Обычно все эти stdin и stdout
могут быть перенаправлены на файлы или в поток
( pipe ), как описывалось в разделе 7.2. лекции №7.
getchar и putchar
могут быть определены в getc, putc, stdin и stdout следующим образом: #define getchar() getc(stdin) #define putchar(c) putc(c, stdout).
При работе с файлами для форматного fscanf и fprintf.
Они идентичны scanf и printf,
за исключением того, что первым
Покончив с предварительными замечаниями, мы теперь в состоянии написать cat для конкатенации файлов. Используемая здесь основная схема
оказывается удобной во многих
#include <stdio.h>
main(argc, argv) /*cat: concatenate files*/
int argc;
char *argv[];
{
file *fp, *fopen();
if(argc==1) /*no args; copy standard input*/
filecopy(stdin);
else
while (--argc > 0)
if ((fp=fopen(*++argv,"r"))==null) {
printf("cat:can't open %\n",*argv);
break;
} else {
filecopy(fp);
fclose(fp);
}
}
filecopy(fp) /*copy file fp to standard output*/
file *fp;
{
int c;
while ((c=getc(fp)) !=EOF)
putc(c, stdout);
}
stdin и stdout
заранее определены в библиотеке file*. Они однако являются
fclose является обратной по
отношению к fopen ; она разрывает связь
между fopen, и высвобождает cat, освободив не
нужные нам более объекты, является хорошей идеей. Имеется и другая причина для
применения fclose к выходному файлу - она вызывает выдачу информации
из буфера, в котором putc собирает fclose вызывается автоматически для каждого открытого
файла).
Обработка ошибок в cat неидеальна.
Неудобство заключается в том, что
если один из файлов по некоторой причине оказывается недоступным, ) механизм в другую
Чтобы лучше обрабатывать такую ситуацию, к stdin и stdout,
присоединяется второй выходной файл, называемый stderr.
Если это вообще возможно, stderr,
появляется на
Давайте переделаем cat таким образом,
чтобы сообщения об ошибках писались в стандартный
"include <stdio.h>
main(argc,argv) /*cat: concatenate files*/
int argc;
char *argv[];
{
file *fp, *fopen();
if(argc==1) /*no args; copy standard input*/
filecopy(stdin);
else
while (--argc > 0)
if((fp=fopen(*++argv,"r#))==null) {
fprintf(stderr,
"cat: can't open,%s\n", argv);
exit(1);
} else {
filecopy(fp);
}
exit(0);
}
printf, поступает в stderr
и, таким образом, оказывается на ) или в выходном файле.
exit из exit
доступен любой
exit вызывает fclose
для каждого открытого выходного файла, с тем чтобы вывести всю
помещенную в буферы выходную информацию, а затем
вызывает _exit. _exit приводит
к немедленному завершению без
очистки каких-либо буферов; конечно, при желании к этой
fgets, совершенно аналогичную getline, которую мы использовали на всем
протяжении книги. В результате обращения
fgets(line, maxline, fp)
следующая строка fp в line ; самое большое maxline-1 символ будет прочитан.
Результирующая строка заканчивается символом \0.
Нормально fgets возвращает line ;
в null. (Наша getline
возвращает длину строки, а при выходе на
Предназначенная для fputs
записывает строку (которая не обязана содержать
fputs(line, fp)
Чтобы показать, что в fgets и fputs нет ничего таинственного, мы приводим их ниже,
скопированными непосредственно из
#include <stdio.h>
char *fgets(s,n,iop) /*get at most n chars from iop*/
char *s;
int n;
register 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) /*put string s on fils iop*/
register char *s;
register file *iop;
{
register int c;
while (c = *s++)
putc(c,iop);
}
Упражнение 7-3
Напишите
Упражнение 7-4
Переделайте
Упражнение 7-5
Напишите
strlen, strcpy, и . Вот некоторые другие.
Некоторые макросы выполняют проверку символов и преобразования:
isalpha(c) не 0, если "c" алфавитный символ,
0 - если нет.
isupper(c) Не 0, если "c" буква верхнего регистра,
0 - если нет.
islower(c) Не 0, если "c" буква нижнего регистра,
0 - если нет.
isdigit(c) Не 0, если "c" цифра,
0 - если нет.
isspace(c) Не 0, если "c" пробел, табуляция
или новая строка, 0 - если нет.
toupper(c) Преобразует "c" в букву верхнего регистра.
tolower(c) Преобразует "c" в букву нижнего регистра.
ungetch,
написанной нами в лекции №4; она называется ungetc. В результате
обращения
ungetc(c,fp)
символ "C" возвращается в файл fp. Позволяется возвращать
в каждый файл только один символ. ungetc может быть
использована в любой из scanf, getc или getchar.
system(s) выполняет команду,
содержащуюся в s,
и затем возобновляет выполнение текущей s сильно зависит от используемой
system("date");
приводит к выполнению date, которая печатает дату и время дня.
calloc весьма сходна с alloc, использованной нами в
предыдущих лекциях. В результате обращения
calloc(n, sizeof(object))
возвращается либо n объектов указанного размера, либо null, если запрос не может быть удовлетворен. Отводимая
память инициализируется нулевыми значениями.
char *calloc(); int *ip; ip=(int*) calloc(n,sizeof(int));
cfree(p) освобождает пространство,
на которое указывает "p",
причем "p" первоначально должен
быть получен в результате обращения к calloc. Здесь нет
никаких ограничений на порядок освобождения пространства, но
будет неприятнейшей ошибкой освободить что-нибудь, что не было получено
обращением к calloc.
Реализация calloc, в которой размещенные блоки могут освобождаться
в произвольном порядке, продемонстрирована в лекции №8.
Средства
Мы здесь не будем пытаться описать всю библиотеку
Каждый
#include <stdio.h>
в файле stdio.h определяются некоторые макросы и /usr/include ).
Кроме того, при загрузке
cc исходные файлы и т.д. -ls
где -ls указывает на загрузку из
Самый простой механизм getchar. getchar()
при каждом к ней обращении возвращает
следующий <: если некоторая prog использует getchar то командная строка
prog<infile
приведет к тому, что prog будет читать
из файла infile, а не с prog не замечает
изменения; в частности строка" <infile " не включается
в командную строку argv. Переключение pipe )
механизма; командная строка
otherprog | prog
прогоняет две otherprog и prog,
и организует так, что стандартным prog служит
стандартный otherprog.
getchar возвращает значение EOF,
когда она попадает на EOF равной -1
(посредством #define в файле stdio.h ), но проверки
следует писать в терминах EOF, а не -1, чтобы избежать
зависимости от конкретного значения.
putchar(c),
помещающей символ 'с' в "стандартный > если prog использует putchar, то командная строка
prog>outfile
приведет к записи стандартного outfile,
а не на
prog | anotherprog
помещает стандартный prog в стандартный anotherprog. И опять prog не
будет осведомлена об изменении направления.
printf,
также поступает в стандартный putchar
и printf могут перемежаться.
Поразительное количество getchar, putchar и printf может оказаться вполне адекватным и
для начала определенно достаточным. Это особенно справедливо тогда, когда
имеется возможность указания файлов для lower, которая преобразует прописные
буквы из своего
#include <stdio.h>
main() /* convert input to lower case */
{
int c;
while ((c = getchar()) != EOF)
putchar(isupper(c) ? tolower(c) : c);
}
" isupper и tolower на
самом деле являются макросами, stdio.h. Макрос isupper проверяет, является ли его tolower преобразует букву из верхнего
регистра в ту же букву нижнего регистра. Независимо от того, как эти
Если требуется преобразовать несколько файлов, то можно собрать эти файлы
с помощью cat
системы
cat file1 file2 ... | lower>output
и избежать тем самым вопроса о том, как обратиться к этим файлам из cat приводится позже в этой лекции).
Кроме того отметим, что в getchar и putchar
на самом деле могут быть макросами. Это позволяет избежать накладных
расходов на
Две printf для scanf
для printf ; здесь
приводится более полное и точное
printf(control, arg1, arg2, ...)
преобразует, определяет формат и печатает свои control. Управляющая строка содержит два printf.
Каждая %
и заканчивается символом преобразования. Между % и символом
преобразования могут находиться:
float или double.l, который указывает,
что соответствующий элемент long,
а не int.Ниже приводятся символы преобразования и их смысл:
d - o - x - 0x ).u - c - s - e - float или double, преобразуется в десятичную форму в виде [-]m.nnnnnne[+-]xx, где длина строки из n определяется
указанной точностью. Точность по умолчанию равна 6.f - float или double, преобразуется в десятичную форму в виде [-]mmm .nnnnn, где длина строки из n определяется указанной
точностью. Точность по умолчанию равна 6. Отметим, что эта
точность не определяет количество печатаемых в формате f
значащих цифр.g - Используется или формат %e или %f,
какой короче; незначащие нули не печатаются. Если идущий за % символ не является символом преобразования, то
печатается сам этот символ; следовательно, символ % можно
напечатать, указав %%.Большинство из форматных преобразований очевидно и было проиллюстрировано
в предыдущих лекциях. Единственным исключением является то, как точность
взаимодействует со строками. Следующая таблица демонстрирует влияние задания
различных hello, world " (12 символов). Мы поместили
двоеточия вокруг каждого поля для того, чтобы вы могли видеть его протяженность.
:%10s: :hello, world: :%10-s: :hello, world: :%20s: : hello, world: :%-20s: :hello, world : :%20.10s: : hello, wor: :%-20.10s: :hello, wor : :%.10s: :hello, wor:
Предостережение: printf использует свой первый
Упражнение 7-1
Напишите
Осуществляющая scanf является аналогом printf и позволяет проводить в обратном направлении многие
из тех же самых преобразований.
scanf(control, arg1, arg2, ...)
читает символы из стандартного control, и помещает результаты в остальные
Управляющая строка обычно содержит
% ), которые предполагаются
совпадающими со следующими отличными от символов пустых промежутков
символами входного потока.%,
необязательного символа подавления присваивания *,
необязательного числа, задающего максимальную ширину поля и символа
преобразования.* указано
подавление присваивания, то это поле scanf будет пересекать границы строк,
поскольку
Символ преобразования определяет интерпретацию поля
d - на o - На x - На 0x или без них); соответствующий h - На short ;
соответствующий short.c - Ожидается отдельный символ; соответствующий %1s.s - Ожидается \0.f - Ожидается число с плавающей точкой; соответствующий float.Е - символ преобразования e
является синонимом для f. Формат float включает необязательный знак,
строку цифр, возможно содержащую десятичную точку и
необязательное поле экспоненты, состоящее из буквы e, за которой
следует целое, возможно имеющее знак.Перед символами преобразования d, o и x может стоять l,
которая означает , что в long, а
не int. Аналогично, буква l может
стоять перед символами преобразования e или f, говоря о том, что в double, а не float.
Например, обращение
int i; float x; char name[50]; scanf("%d %f %s", i, x, name);
со строкой на
25 54.32e-1 thompson
приводит к присваиванию i значения 25, x - значения 5.432 и name - строки
" thompson ", надлежащим образом законченной символом \0. эти три поля
int i;
float x;
char name[50];
scanf("%2d %f %*d %2s", i, x, name);
с
56789 0123 45a72
присвоит i значение 56, x - 789.0, пропустит 0123
и поместит в name строку "45".
При следующем обращении к любой a. В этих двух примерах name является .
В качестве другого примера перепишем теперь элементарный калькулятор из
лекции №4, используя для преобразования scanf:
#include <stdio.h>
main() /* rudimentary desk calculator */
{
double sum, v;
sum =0;
while (scanf("%lf", v) !=EOF)
printf("\t%.2f\n", sum += v);
}
выполнение scanf заканчивается
либо тогда, когда она исчерпывает свою
управляющую строку, либо когда некоторый элемент EOF ; подчеркнем, что это значение
отлично от 0, что следующий scanf поиск возобновляется непосредственно за
последним введенным символом.
Заключительное предостережение: scanf должны быть
scanf("%d", n);
вместо
scanf("%d", n);
От scanf и printf
происходят sscanf и sprintf, которые
осуществляют аналогичные преобразования, но оперируют со строкой, а не с файлом.
sprintf(string, control, arg1, arg2, ...) sscanf(string, control, arg1, arg2, ...)
Как и раньше , sprintf преобразует свои arg1, arg2 и т.д. В соответствии с форматом, указанным
в control, но помещает результаты в string, а
не в стандартный string должна быть
достаточно велика, чтобы принять результат. Например, если name - это n - целое, то
sprintf(name, "temp%d", n);
создает в name строку вида tempnnn,
где nnn - значение n.
sscanf выполняет обратные
преобразования - она просматривает строку string
в соответствии с форматом в control и помещает результирующие значения в arg1, arg2 и т.д. Эти
sscanf(name, "temp%d", n);
n получает значение строки цифр,
следующих за temp в name.
Упражнение 7-2
Перепишите настольный калькулятор из лекции №4, используя для scanf и/или sscanf.
Все до сих пор написанные
Следующим шагом в вопросе cat, которая объединяет набор из нескольких
именованных файлов в стандартный cat
используется для
cat x.c,y.c
печатает содержимое файлов x.c и y.c
в стандартный
Вопрос состоит в том, как организовать чтение из именованных файлов,
т.е., как связать внешние имена, которыми мыслит пользователь, с фактически
читающими
Эти правила просты. Прежде чем можно считывать из некоторого файла или
записывать в него, этот файл должен быть открыт с помощью fopen из fopen берет внешнее имя (подобное x.c
или y.c ), проводит некоторые обслуживающие действия и переговоры с
Это внутреннее имя, называемое " stdio.h, содержится file. Единственное необходимое для
file *fopen(), *fp;
Здесь говорится, что fp является file и fopen возвращает file. Oбратите внимание, что file
является именем int, а
не ярлыку typedef.
(Подробности того, как все это работает на системе
Фактическое fopen в
fp=fopen(name,mode);
Первым fopen является "имя" файла, которое задается в
виде mode("режим") также является r "), запись (" w ")
и добавление (" a ").
Если вы откроете файл, который еще не существует, для записи или добавления, то такой файл будет создан (если это возможно).
Открытие существующего файла на запись приводит к отбрасыванию его старого
содержимого. Попытка чтения несуществующего файла является ошибкой. Ошибки
могут быть обусловлены и другими причинами (например, попыткой
чтения из файла, не имея на то разрешения). При наличии какой-либо
ошибки null (которое для
удобства также определяется в файле stdio.h ).
Другой необходимой вещью является способ чтения или записи, если файл
уже открыт. Здесь имеется несколько возможностей, из которых getc
и putc являются простейшими. getc
возвращает следующий символ из файла; ей
необходим
c=getc(fp)
помещает в "C" следующий символ из файла, указанного посредством fp, и EOF, если достигнут
putc, являющаяся getc,
putc(c,fp)
помещает символ " c " в файл fp и возвращает " c ".
Подобно getchar и putchar, getc и putc
могут быть макросами, а не
При запуске stdin, stdout и stderr. Обычно все эти stdin и stdout
могут быть перенаправлены на файлы или в поток
( pipe ), как описывалось в разделе 7.2. лекции №7.
getchar и putchar
могут быть определены в getc, putc, stdin и stdout следующим образом: #define getchar() getc(stdin) #define putchar(c) putc(c, stdout).
При работе с файлами для форматного fscanf и fprintf.
Они идентичны scanf и printf,
за исключением того, что первым
Покончив с предварительными замечаниями, мы теперь в состоянии написать cat для конкатенации файлов. Используемая здесь основная схема
оказывается удобной во многих
#include <stdio.h>
main(argc, argv) /*cat: concatenate files*/
int argc;
char *argv[];
{
file *fp, *fopen();
if(argc==1) /*no args; copy standard input*/
filecopy(stdin);
else
while (--argc > 0)
if ((fp=fopen(*++argv,"r"))==null) {
printf("cat:can't open %\n",*argv);
break;
} else {
filecopy(fp);
fclose(fp);
}
}
filecopy(fp) /*copy file fp to standard output*/
file *fp;
{
int c;
while ((c=getc(fp)) !=EOF)
putc(c, stdout);
}
stdin и stdout
заранее определены в библиотеке file*. Они однако являются
fclose является обратной по
отношению к fopen ; она разрывает связь
между fopen, и высвобождает cat, освободив не
нужные нам более объекты, является хорошей идеей. Имеется и другая причина для
применения fclose к выходному файлу - она вызывает выдачу информации
из буфера, в котором putc собирает fclose вызывается автоматически для каждого открытого
файла).
Обработка ошибок в cat неидеальна.
Неудобство заключается в том, что
если один из файлов по некоторой причине оказывается недоступным, ) механизм в другую
Чтобы лучше обрабатывать такую ситуацию, к stdin и stdout,
присоединяется второй выходной файл, называемый stderr.
Если это вообще возможно, stderr,
появляется на
Давайте переделаем cat таким образом,
чтобы сообщения об ошибках писались в стандартный
"include <stdio.h>
main(argc,argv) /*cat: concatenate files*/
int argc;
char *argv[];
{
file *fp, *fopen();
if(argc==1) /*no args; copy standard input*/
filecopy(stdin);
else
while (--argc > 0)
if((fp=fopen(*++argv,"r#))==null) {
fprintf(stderr,
"cat: can't open,%s\n", argv);
exit(1);
} else {
filecopy(fp);
}
exit(0);
}
printf, поступает в stderr
и, таким образом, оказывается на ) или в выходном файле.
exit из exit
доступен любой
exit вызывает fclose
для каждого открытого выходного файла, с тем чтобы вывести всю
помещенную в буферы выходную информацию, а затем
вызывает _exit. _exit приводит
к немедленному завершению без
очистки каких-либо буферов; конечно, при желании к этой
fgets, совершенно аналогичную getline, которую мы использовали на всем
протяжении книги. В результате обращения
fgets(line, maxline, fp)
следующая строка fp в line ; самое большое maxline-1 символ будет прочитан.
Результирующая строка заканчивается символом \0.
Нормально fgets возвращает line ;
в null. (Наша getline
возвращает длину строки, а при выходе на
Предназначенная для fputs
записывает строку (которая не обязана содержать
fputs(line, fp)
Чтобы показать, что в fgets и fputs нет ничего таинственного, мы приводим их ниже,
скопированными непосредственно из
#include <stdio.h>
char *fgets(s,n,iop) /*get at most n chars from iop*/
char *s;
int n;
register 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) /*put string s on fils iop*/
register char *s;
register file *iop;
{
register int c;
while (c = *s++)
putc(c,iop);
}
Упражнение 7-3
Напишите
Упражнение 7-4
Переделайте
Упражнение 7-5
Напишите
strlen, strcpy, и . Вот некоторые другие.
Некоторые макросы выполняют проверку символов и преобразования:
isalpha(c) не 0, если "c" алфавитный символ,
0 - если нет.
isupper(c) Не 0, если "c" буква верхнего регистра,
0 - если нет.
islower(c) Не 0, если "c" буква нижнего регистра,
0 - если нет.
isdigit(c) Не 0, если "c" цифра,
0 - если нет.
isspace(c) Не 0, если "c" пробел, табуляция
или новая строка, 0 - если нет.
toupper(c) Преобразует "c" в букву верхнего регистра.
tolower(c) Преобразует "c" в букву нижнего регистра.
ungetch,
написанной нами в лекции №4; она называется ungetc. В результате
обращения
ungetc(c,fp)
символ "C" возвращается в файл fp. Позволяется возвращать
в каждый файл только один символ. ungetc может быть
использована в любой из scanf, getc или getchar.
system(s) выполняет команду,
содержащуюся в s,
и затем возобновляет выполнение текущей s сильно зависит от используемой
system("date");
приводит к выполнению date, которая печатает дату и время дня.
calloc весьма сходна с alloc, использованной нами в
предыдущих лекциях. В результате обращения
calloc(n, sizeof(object))
возвращается либо n объектов указанного размера, либо null, если запрос не может быть удовлетворен. Отводимая
память инициализируется нулевыми значениями.
char *calloc(); int *ip; ip=(int*) calloc(n,sizeof(int));
cfree(p) освобождает пространство,
на которое указывает "p",
причем "p" первоначально должен
быть получен в результате обращения к calloc. Здесь нет
никаких ограничений на порядок освобождения пространства, но
будет неприятнейшей ошибкой освободить что-нибудь, что не было получено
обращением к calloc.
Реализация calloc, в которой размещенные блоки могут освобождаться
в произвольном порядке, продемонстрирована в лекции №8.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.