рефераты

рефераты

 
 
рефераты рефераты

Меню

Реферат: Язык С рефераты

или 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 заканчивается либо тогда, когда она

исчерпывает свою управляющую строку, либо когда некоторый

элемент ввода не совпадает с управляющей спецификацией. В

качестве своего значения она возвращает число правильно сов-

падающих и присвоенных элементов ввода. Это число может быть

    

·     159 -

    

использовано для определения количества найденных элементов

ввода. при выходе на конец файла возвращается EOF; подчерк-

нем, что это значение отлично от 0, что следующий вводимый

символ не удовлетворяет первой спецификации в управляющей

строке. При следующем обращении к SCANF поиск возобновляется

непосредственно за последним введенным символом.

Заключительное предостережение: аргументы функции SCANF

должны быть указателями. Несомненно наиболее распространен-

ная ошибка состоит в написании

 

SCANF(“%D”, N);

вместо

SCANF(“%D”, &N);

7.5.   Форматное преобразование в памяти

 

 

 

От функции SCANF и PRINTF происходят функции SSCANF и

SPRINTF, которые осуществляют аналогичные преобразования, но

оперируют со строкой, а не с файлом. Обращения к этим функ-

циям имеют вид:

 

SPRINTF(STRING, CONTROL, ARG1, ARG2, ...)

SSCANF(STRING, CONTROL, ARG1, ARG2, ...)

Как и раньше , функция SPRINTF преобразует свои аргументы

ARG1, ARG2 и т.д. В соответствии с форматом, указанным в

CONTROL, но помещает результаты в STRING, а не в стандартный

вывод. KОнечно, строка 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.

·                 
160 -

    

7.6.             Доступ к файлам

Все до сих пор написанные программы читали из стандарт-

ного ввода и писали в стандартный вывод, относительно кото-

рых мы предполагали, что они магическим образом предоставле-

ны программе местной операционной системой.

Следующим шагом в вопросе ввода-вывода является написа-

ние программы, работающей с файлом, который не связан зара-

нее с программой. одной из программ, которая явно демонстри-

рует потребность в таких операциях, является 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. (Подробности того, как

все это работает на системе UNIX, приведены в главе 8).

Фактическое обращение к функции FOPEN в программе имеет

вид:

FP=FOPEN(NAME,MODE);

·                 
161 -

    

Первым аргументом функции 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.

Функции GETCHAR и PUTCHAR могут быть определены в терми-

налах GETC, PUTC, STDIN и STDOUT следующим образом:

#DEFINE GETCHAR() GETC(STDIN) #DEFINE PUTCHAR©  PUTC(C,

STDOUT)

При работе с файлами для форматного ввода и вывода можно ис-

пользовать функции FSCANF и FPRINTF. Они идентичны функциям

SCANF и PRINTF, за исключением того, что первым аргументом

является указатель файла, определяющий тот файл, который бу-

дет читаться или куда будет вестись запись; управляющая

строка будет вторым аргументом.

    

·     162 -

    

Покончив с предварительными замечаниями, мы теперь в

состоянии написать программу 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 вызы-

вается автоматически для каждого открытого файла).

·          
163 -

 

7.7.             Обработка ошибок - STDERR и EXIT

Обработка ошибок в CAT неидеальна. Неудобство заключает-

ся в том, что если один из файлов по некоторой причине ока-

зывается недоступным, диагностическое сообщение об этом пе-

чатается в конце объединенного вывода. Это приемлемо, если

вывод поступает на терминал, но не годится, если вывод пос-

тупает в некоторый файл или через поточный (PIPELINE) меха-

низм в другую программу.

Чтобы лучше обрабатывать такую ситуацию, к программе

точно таким же образом, как 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) \(

PRINTF(STDERR,

“CAT: CAN'T OPEN,%S\N”, ARGV);

EXIT(1);

\) ELSE \(

FILECOPY(FP);

   \)

EXIT(0);

    \)

 

Программа сообщает об ошибках двумя способами. Диагностичес-

кое сообщение, выдаваемое функцией FPRINTF, поступает в

STDERR и, таким образом, оказывается на терминале пользова-

теля, а не исчезает в потоке (PIPELINE) или в выходном фай-

ле.

Программа также использует функцию EXIT из стандартной

библиотеки, обращение к которой вызывает завершение выполне-

ния программы. Аргумент функции EXIT доступен любой програм-

ме, обращающейся к данной функции, так что успешное или неу-

дачное завершение данной программы может быть проверено дру-

гой программой, использующей эту в качестве подзадачи. По

соглашению величина 0 в качетсве возвращаемого значения сви-

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

значения являются признаками нормальных ситуаций.

    

·     164 -

    

Функция EXIT вызывает функцию FCLOSE для каждого откры-

того выходного файла, с тем чтобы вывести всю помещенную в

буферы выходную информацию, а затем вызывает функцию _EXIT.

Функция _EXIT приводит к немедленному завершению без очистки

каких-либо буферов; конечно, при желании к этой функции мож-

но обратиться непосредственно.

 

7.8.   Ввод и вывод строк

Стандартная библиотека содержит функцию 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) 7 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);

    \)     

·     165 -

 

 

Упражнение 7-3.

Напишите программу сравнения двух файлов, которая будет

печатать первую строку и позицию символа, где они различают-

ся.

Упражнение 7-4.

Переделайте программу поиска заданной комбинации симво-

лов из главы 5 таким образом, чтобы в качестве ввода исполь-

зовался набор именованных файлов или, если никакие файлы не

указаны как аргументы, стандартный ввод. Следует ли печатать

имя файла при нахождении подходящей строки?

Упражнение 7-5.

Напишите программу печати набора файлов, которая начина-

ет каждый новый файл с новой страницы и печатает для каждого

файла заголовок и счетчик текущих страниц.

7.9.   Несколько разнообразных функций

Стандартная библиотека предоставляет множество разнооб-

разных функций, некоторые из которых оказываются особенно

полезными. Мы уже упоминали функции для работы со строками:

STRLEN, STRCPY, STRCAT и STRCMP. Вот некоторые другие.

 

7.9.1.                Проверка вида символов и преобразования

Некоторые макросы выполняют проверку символов и преобра-

зования:

 

SALPHA© не 0, если “C” алфавитный символ,

0 - если нет.

SUPPER© Не 0, если “C” буква верхнего регистра,

0 - если нет.

SLOWER© Не 0, если “C” буква нижнего регистра,

0 - если нет.

SDIGIT© Не 0, если “C” цифра,

0 - если нет.

SSPACL© Не 0, если “C” пробел, табуляция

или новая строка, 0 - если нет.

OUPPER© Преобразует “C” в букву верхнего регистра.

OLOWER© Преобразует “C” в букву нижнего регистра.

 

7.9.2.                Функция UNGETC

Стандартная библиотека содержит довольно ограниченную

версию функции UNGETCH, написанной нами в главе 4; она назы-

вается UNGETC. В результате обращения

 

UNGETC(C,FP)

символ “C” возвращается в файл FP. Позволяется возвращать в

каждый файл только один символ. Функция UNGETC может быть

использована в любой из функций ввода и с макросами типа

SCANF, GETC или GETCHAR.

    

·     166 -

 

7.9.3.         Обращение к системе

Функция SYSTEM(S) выполняет команду, содержащуюся в сим-

вольной строке S, и затем возобновляет выполнение текущей

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28