Суббота, 27.04.2024, 00:02
Приветствую Вас Гость | RSS

Программирование на ЯВУ

Меню сайта
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа

Лекция 15

Стандартные библиотечные функции

Библиотека языка Си содержит множество функций и макроопределений. Библиотеки меняются от системы к системе, но есть ядро функций (стандартная библиотека).

Эти функции используются для:

  • манипулирования данными, их преобразования и шифрования;
  • определения пользователями функций с переменным числом аргументов;
  • динамического управления памятью;
  • представления показаний системных часов в стандартных форматах даты и времени;
  • получения системной информации.

Главными преимуществами стандартных библиотечных функций Си являются мобильность и низкие затраты на сопровождение пользовательских приложений. Библиотечные функции не подвержены частым изменениям, поэтому программы, в которых они используются, легки в сопровождении. Некоторые из этих библиотечных функций соответствуют стандарту ANSI С - стандарту Си Американского национального института, благодаря чему они приемлемы для всех систем, соответствующих этому стандарту. Чтобы сократить затраты и время на разработку приложений, рекомендуется использовать библиотечные функции Си всякий раз, когда это оказывается возможным.

Стандартные библиотечные функции Си объявляются в наборе файлов-заголовков, которые в UNIX-системах обычно расположены в каталоге /usr/include. Опишем библиотечные функции ANSI C, определенные в файлах-заголовков, перечисленных ниже:

<stdio.h>
<stdlib.h>
<string.h>
<memory.h>
<malloc.h>
<time.h>
<assert.h>
<stdarg.h>
<getopt.h>
<setjmp.h>

Кроме указанных, в большинстве UNIX-систем есть файлы заголовков, которые не определены в ANSI C:

<pwd.h>
<grp.h>
<crypt.h>.

В этих файлах заголовков объявляются функции, которые помогают получить доступ к информации о бюджетах пользователей и групп в UNIX-системах. В указанных системах они определены в библиотеке libc.a. Эти функции полезны для разработки приложений.

В файле заголовков <stdio.h> объявляется тип данных FILE, который используется в Си-программах для обозначения потоковых файлов, или просто потоков, т.е. файлов, обмен с которыми осуществляется с помощью функций потокового ввода-вывода. Имеется также набор макрокоманд и функций, предназначенных для манипулирования потоковыми файлами. Ниже приведены некоторые из этих макрокоманд и функций, которые уже должны быть знакомы из предыдущих лекций.

Потоковая функция или макрокоманда Назначение
fopen Открывает поток для чтения и (или) записи
fclose Закрывает поток
fread Читает блок данных из потока
fgets Читает строку текста из потока
fscanf Читает форматированные данные из потока
fwrite Записывает блок данных в поток
fputs Записывает строку текста в поток
fprintf Записывает форматированные данные в поток
fseek Перемещает указатель чтения или записи в потоке
ftell Возвращает текущую позицию в потоке, начиная с которой будет выполнена следующая операция чтения или записи. Возвращаемое значение - это количество байтов смещения относительно начала потока
freopen Повторно использует указатель потока для ссылки на новый файл
fdopen Открывает потоковый файл с указанным дескриптором
feof Макрокоманда, которая возвращает ненулевое значение, если в данном потоке обнаружен символ конца файла, в противном случае - нулевое значение
ferror Макрокоманда, которая возвращает ненулевое значение, если в данном потоке была обнаружена ошибка или символ конца файла, в противном случае - нулевое значение
clearer Макрокоманда, которая сбрасывает флаг наличия ошибок в данном потоке
fileno Макрокоманда, которая возвращает дескриптор данного потокового файла

В заголовке <stdlib.h> объявляется набор функций, служащих для преобразования данных, генерации случайных чисел, получения и установки переменных среды shell, управления выполнением программ и выполнения команд shell. Обычно эти функции объявляются в заголовке <stdio.h>, но так как они не включают в себя манипулирование потоками, стандарт ANSI C группирует их в отдельный заголовок.

В заголовке <string.h> объявляется набор функций, предназначенных для манипулирования символьными строками.

В заголовке <memory.h> объявляется набор функций, предназначенных для манипулирования байтовым потоком. Эти функции похожи на строковые, но в отличие от них имеют более широкое назначение и могут использоваться для манипулирования несимвольными строковыми объектами. В частности, данные функции можно применять для инициализации, сравнения и копирования объектов типа struct.

В заголовке <time.h> объявляется набор функций, предназначенных для вызова системных параметров времени. Они могут применяться для определения местного времени и даты, времени и даты в универсальном формате (UTC), а также статистических данных об использовании процессами времени центрального процессора.

В заголовке <assert.h> объявляется макрокоманда, используемая для проверки некоторых условий выполнения процесса, которые в нормальной ситуации всегда должны быть истинны. Если все же во время выполнения процесса условие не выполняется, то макрокоманда выводит сообщение об ошибке в стандартный поток ошибок с указанием той строки исходного файла, в которой нарушается проверяемое условие. После этого макрокоманда прерывает процесс.

В заголовке <setjmp.h> объявляется набор функций, которые позволяют процессу вызывать оператор перехода goto из одной функции в другую. Вызов Си-оператора goto позволяет процессу передать управление выполнением от одного оператора к другому лишь в рамках этой же функции. Функции, определенные в заголовке <setjmp.h> устраняют данное ограничение. Эти функции необходимо использовать лишь тогда, когда без них действительно нельзя обойтись. Например, если ошибка обнаружена в рекурсивной функции, то есть смысл сообщить об ошибке, а затем выполнить оператор перехода goto в основную функцию, т.е. как бы начать процесс сначала.

В заголовке <pwd.h> определяется набор функций, предназначенных для получения учетной информации о пользователях.

В заголовке <grp.h> определяется набор функций, предназначенных для получения учетной информации о группах, содержащейся в UNIX-файле /etc/group.

В заголовке <crypt.h> объявляется набор функций, предназначенных для шифрования и дешифрования данных. Это очень важные функции, обеспечивающие безопасность системы. Например, файлы пользовательских паролей и системных данных, которым необходима высокая степень защиты, должны быть зашифрованы так, чтобы ни один человек, не имеющий специального разрешения, не мог узнать, что они из себя представляют. Более того, чтобы читать и изменять эти объекты, уполномоченные лица должны знать секретные ключи дешифровки.

Доступ в библиотеку языка Си

Получение доступа к библиотеке зависит от системы. Во-первых, есть несколько различных мест расположения библиотечных функций, Например, getchar( ) обычно задают как макроопределение в файле stdio.h, в то время как strlen( ) обычно хранится в библиотечном файле. Во-вторых, различные системы имеют разные способы доступа к этим функциям. Вот три из них.

Автоматический доступ

Во многих больших системах UNIX вы только компилируете программы. А доступ к более общим библиотечным функциям выполняется автоматически.

Включение файла

Если функция задана как макроопределение, то можно директивой #include включить файл, содержащий ее определение. Часто подобные функции могут быть собраны в соответствующим образом названный заголовочный файл. Например, некоторые системы имеют файл ctype.h, содержащий макроопределения, задающие тип символа (прописная буква, цифра и т.д.)

Включение библиотеки

На некотором этапе компиляции или загрузки программы вы можете выбрать библиотеку. Даже система, которая автоматически контролирует свою стандартную библиотеку, может иметь другие библиотеки редко применяемых функций, и эти библиотеки следует запрашивать явно, указывая соответствующий признак во время компиляции.

Очевидно, мы не сможем рассмотреть все особенности всех систем, но эти три примера показывают, что вас ожидает!

Связь с файлами

Один способ организации связи программы с файлом заключается в использовании операций переключения < и >. Этот метод прост, но ограничен. Язык Си предоставляет и более мощные методы связи с файлами. Рассмотрим использование функции fopen( ), которая открывает файл, затем применяются специальные функции ввода-вывода для чтения файла или записи в этот файл и далее используется функция fclose( ) для закрытия файла. Прежде чем исследовать эти функции, кратко познакомимся с сущностью файла.

Файл является частью памяти, обычно на диске, со своим именем. Мы считаем, что он содержит некоторую полезную информацию. Для операционной системы файл более сложен, но это системные проблемы, а не наши. Но мы должны знать, что означает файл для программы на языке Си. В предлагаемых для обсуждения функциях, работающих с файлами, язык Си рассматривает файл как структуру. Вот типичный пример, взятый из IBM-версии компилятора Lattice C:

struct_iobuf {
 char*_ptr; /* текущий указатель буфера*/
 int_cnt; /* текущий счетчик байтов*/
 char*_base; /* базовый адрес буфера ввода-вывода*/
 char_flag; /* управляющий признак*/
 char_file; /* номер файла*/
}
#define FILE struct_iobuf /* краткая запись*/

Здесь мы не собираемся разбираться детально в этом определении. Главное состоит в том, что файл является структурой, и что краткое наименование шаблона - FILE. Многие системы используют директиву typedef для установления этого соответствия. Таким образом, программа, имеющая дело с файлами, будет использовать тип структуры FILE, чтобы делать так.

Рассмотрим пример чтения содержимого файла, названного File, и вывода его на экран:

#include <stdio.h>
main( )
{
 FILE *in; /* описываем указатель на файл */
 int ch;
 if ((in = fopen("File", "r") ) != NULL) {
 /* открываем File для чтения, 
 проверяя существует ли он */ 
 /* указатель FILE ссылается теперь на File */
 while ((ch = getc(in)) != EOF)
 /* получаем символ из in */
 putc(ch, stdout); 
 /* посылаем ch на стандартный вывод*/
 fclose(in); /* закрываем файл */
 }
 else 
 printf (" Файл не открывается\"File\".\n");
}

Объясним работу: fopen( ), fclose и использование функций ввода-вывода файла.

Открытие файла: fopen( )

Функцией fopen( ) управляют три основных параметра. Первый - имя файла, который следует открыть. Он является и первым аргументом fopen( ). В нашем примере это "File". Второй параметр описывает, как должен использоваться файл:

"r" - файл нужно считать,

"w" - файл нужно записать,

"a" - файл нужно дополнить.

"w+" - новый текстовый файл открывается для записи и последующих многократных исправлений. Если файл уже существует, то предыдущее содержимое стирается. Последующие после открытия файла запись и чтение из него допустимы в любом месте файла, в том числе запись разрешена и в конце файла, т.е. файл может увеличиваться.

"r+" - существующий текстовый файл открывается как для чтения, так и для записи в любом месте файла; однако в этом режиме невозможна запись в конец файла, то есть недопустимо увеличение размеров файла.

"a+" - текстовый файл открывается или создается, если файла нет, и становится доступным для изменений, т.е. для записи и для чтения в любом месте; при этом в отличие от режима "w+"можно открыть существующий файл и не уничтожать его содержимое; в отличие от режима "r+" в режиме "a+" можно вести запись в конец файла, то есть увеличивать его размеры.

Некоторые системы предоставляют еще дополнительные возможности, которые мы здесь не будем рассматривать. Используемые коды являются строками, а не символьными константами. При применении "r" открывается существующий файл. При двух других применениях тоже будет открываться существующий файл, но если такого файла нет, он будет создан. Если вы используете "w" для существующего файла, то старая версия его стирается, и ваша программа начинает записывать на чистое место. Третий параметр является указателем на файл. Это значение возвращается самой функцией:

FILE *in;
in=fopen("File","r"); 

Теперь in является указателем на файл "File". С этого момента программа ссылается на файл при помощи указателя in, а не по имени File. (Файл stdio.h содержит строку

FILE *fopen( )

Если fopen( ) не способна открыть требуемый файл, она возвращает значение NULL, определенное в stdio.h как 0.

Закрытие файла: fclose( )

В нашем примере показано, как нужно закрывать файл:

fclose(in);

Аргумент функции является указателем на файл. Для более серьезной программы нужно смотреть, успешно ли закрыт файл. Функция fclose( ) возвращает значение 0, если файл закрыт успешно, и EOF в противном случае.

Текстовые файлы с буферизацией

Функции fopen( ) и fclose( ) работают с текстовыми файлами с "буферизацией". Под буферизацией мы понимаем, что вводимые и выводимые данные запоминаются во временной области памяти, называемой буфером. Если буфер заполнился, содержимое его передается в блок, и процесс буферизации начинается снова. Одна из основных задач fclose( ) заключается в том, чтобы освободить любые частично заполненные буферы, если файл закрыт. Текстовым считается файл, в котором информация запоминается в виде символов в коде ASCII или аналогичном. Текстовый файл отличается от двоичного файла, который обычно используется для запоминания кодов машинного языка.

Ввод-вывод текстового файла: getc( ), putc( )

Две функции getc( ) и putc( ) работают аналогично функциям getchar( ) и putchar( ) (описанным в предыдущих лекциях). Разница заключается в том, что вы должны сообщить, какой файл следует использовать.

char ch;
ch=getchar( );

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

ch=getc(in);

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

putchar(ch);

выводит символ на стандартный файл вывода.

putc(ch,t);

предназначена для записи символа ch в файл, на который ссылается указатель t типа FILE.

Ввод-вывод файла: fprintf( ), fscanf( ), fgets( ), fputs( )

Все функции ввода-вывода, которые мы использовали в предыдущих лекциях, имеют аналоги для ввода-вывода файла. Основное отличие состоит в том, что нам нужно использовать указатель типа FILE , чтобы сообщить функциям с каким файлом им следует работать. Подобно getc( ) и putc( ) эти функции используются после функции fopen( ), открывающей файл, и перед fclose( ), закрывающей его.

Функции fprintf( ) и fscanf( )

Эти функции ввода-вывода работают почти как printf( ) и scanf( ) (см. лекцию 4), но им нужен дополнительный аргумент для ссылки на сам файл. Он является первым в списке аргументов. Пример, иллюстрирующий обращение к этим функциям:

#include <stdio.h>
main( )
{
 FILE *fi;
 int age;
 fi=fopen("File","r"); /* считывание */
 fscanf(fi,"%d",&age); /* fi указывает на File */
 fclose(fi);
 fi=fopen("Data", "a"); /*дополнение*/
 fprintf(fi,"Data is %d.\n",age); 
 /*fi указывает на Data*/
 fclose(fi);
}

В отличие от getc( ) и putc( ) эти функции получают указатель типа FILE в качестве первого аргумента.

Функция fgets( )

Эта функция имеет три аргумента, в то время как gets( ) имеет лишь один. Пример ее использования:

/* Программа считывает файл строка за строкой */
#include <stdio.h>
#define MAX 80
main( )
{
 FILE *f1;
 char *string[MAX];
 f1=fopen("File","r");
 while (fgets(string,MAX,f1) != NULL)
 puts(string);
}

Мы расположили вводимую информацию в символьном массиве string. Первый из трех аргументов функции fgets( ) является указателем на местоположение считываемой строки. Второй аргумент содержит предельную длину считываемой строки. Функция прекращает работу после считывания символа новой строки или после считывания символов общим числом MAX-1, в зависимости от того, что произойдет раньше. В любом случае нуль-символ '\0' добавляется в самый конец строки. Третий аргумент указывает на файл, который будет читаться. Разница между gets( ) и fgets( ) заключается в том, что gets( ) заменяет символ новой строки на '\0', в то время как fgets( ) сохраняет символ новой строки. Подобно gets( ) функция fgets( ) возвращает значение NULL, если встречает символ EOF . Это позволяет нам проверить, достигли ли мы конца файла.

Функция fputs( )

Эта функция похожа на функцию puts( ). Оператор

l=fputs("Строка", fi);
Код Положение в файле
0начало файла
1текущая позиция
2конец файла

Передает строку "Строка" в файл, на который ссылается указатель fi типа FILE. Конечно, сначала нужно открытßW  ê · ! á  TW.¾q’ýߝ ê·! á K573#N75-76<6<4-(Èíí9(hJJn;%t2H¾ H¾ mbN]HELß L ß9lx;bC2"  "  88­Il¤@ð ! á ï ž 0ð ž ! á ï (9H>;C=E9Ƥ.½ û=FGÀ%Y Z — û  _›¨ z›¦èôl­ÍÀÐ U a é ¾ !¯ #æ $Ÿ %د û=FGÀ%YZ—û_›¨a  z›¦èôl­ÍÀÐ U é ¾ æ Ÿ ¹*09.2'M<"/C1,6-/-3#91E47$'2##2),*9;=1aãX *€ì© *€© ìZN3l/è p"_&Ø,þ îg   )  öf . 5 6 8 = @ A P Q ä ™ ÷ ¢f,þ÷  îg)Âö . 5 6 8 = @ A P Q ä ™  #+0+/51$/9E','$"$(&L"%6;K 2Cj  Cj   wßgKÖøJXáè Z } '‘ uMYZ[k!‰#T$s&×'>)g+¡,• - /q 0> 4` 6Ž 8º> cJaXaèaaZa}aa‘a aaMaYaZa[aŽ aka‰asa>aga a` aá'uTס• q ` `I````U` ``D`````` `f ```7=`z` P `"`‡ØÃ~0 O. Ó  $ O . Ó jKhžua(§òE)X;é娎ÐOˆ<z‘Ÿ ¡ý¯„ ¡ Õ  $ ÓÆ ¡ 2 f<z‘Ÿ ¡ý¯2 „¡Õ$ÓÆ ¡ UG\iOZE<HHWdc-– $??a `E¡.<ý‚ ýb‚` %E3µ<€öÅkÑ8lã* e K Ê Ì ý  M `öÅkÑ8lãM *eKÊÌý  P>V^XIHCUeKLtK :na¡X 0,ó o 0,o ó '*#0-c´$ÿÿa `‡ìž~0ù+ $ùîœ ¸+-9(98,(¸u  7a ŒX B[’: B’[: j|vHN´fECpMCMp}Kf;8á2õf õf fua6ÖX GÛ^5 GÛ5 ^P9+h(Œ8(”!Cææ6­a”¤@" Ê1»v ˜ ¦ 0" Ê1¦ »v ˜ (EEy>:XB5ED<Í  Í b`;a'E2"  "  ;;(µºûûCaê#X û¸Ø ûØ ¸9:8+( ²  —¥ÿüP ! # $%&ó<aaa a!a&a#a$a%aóad``````` ` ``(fP'33N µÈè\ÿºn! M w ý I ¥»È j º ú ÿ * [ ] Š  ² –! j ú è\ÿºnMw² ýI¥»Èº ÿ * [ ] Š  – '45Y/!6I,,71,27,/y™4/J03*#30¥ –œ0ùò¼e  ’ $ùaòa a’ a¼ae a<` ````` ;ËV2úa  úa  q7ND: E^   ^ $)=-׋$EEa `-;È/$åå |(9ºBûûlX;éìàWOˆå#eªa á  , 0 = y Û & ˆ Õ ß  få#eªa á  ,  0 = y Û & ˆ Õ ß U!.#1!!$ E¶&<@ a@a ``(â2N(ÖKK9(â¸ýýYNq»E$< $< WTj(ºu  7 LJhåæ½\ð^Pšn w Ý ” ˜ Nåæ½\ð^wPšnÝ” ˜ A8),?2/0!."/!tìk(7×ØÙë7×ëØÙ2,*#*;ÛU2>P  >P  z®J'hAF]  ] F]x7Ysp–þg ­®”­ ®”#E˜Uhwp(Ñ0::ƒ(¨òEÓDWÊPåúf©'" I · <åúf· ©'" I 2h8€R…¹3IM=;mg)2Cp Cp Ry("^‡"û~0$ÅR±¢ à $$ÅR¢ ±à ¡m½˜tqÀ‰Ø·HåÚ   Ð 0 Ì Ó 6åÚ  Ó Ì  Ð 0 -*1)3$2*&$f„l] @± L L @± C))M[(ÙÛ>(ËX$NN-(1›EN˜KEéó é óI|Z(i )..(tP®k(ëîwÀéëîéwÀ"L-ŽI:«@1`5ðLp¿ H w¦ g " 3 Hg b3 b5aðaLapa¿aHawa¦a" a }` `` ` `` ` ` Õ` `` (׬CCua”lX `õ×`×õNHadOŒ;F€$qrsd¨­ß ÷ V óàw `ß$qrsd¨à­÷Vów Z>A-9D;;2EYh.(E2#Ì3NXE456465B<7;2þ;  þ;  +%E’^<78 7a8a``;Ì5 2_ _ 62@Ä7‹ ‹a[`aÐX ´j× ´× j,4-(X™lOˆ%1и. Так, malloc(BLOCK) требует 100 байт. Функция возвращает указатель на тип char в начало нового блока памяти. Мы использовали описание

char *malloc( );

чтобы предупредить компилятор, что malloc( ) возвращает указатель на тип char. Поэтому мы присвоили значение этого указателя элементу массива starts[index] при помощи оператора

starts[index]=malloc(BLOCK); 

Предположим, что мы хотим работать с памятью типа int, а не char. Mожете и здесь использовать malloc( ). Вот как это делается:

char malloc( ); 
/* по-прежнему описываем как указатель на char */
int *newmem; newmem = (int *)malloc(100); 
/* используем операцию приведения типа */ 

Снова требуется 100 байт. Операция приведения типа преобразует значение, возвращенное указателем на тип char, в указатель на тип int. Если в системе int. занимает два байта памяти, это значит, что 100 байт можно использовать для запоминания 50 целых чисел.

Функция calloc( )

Другую возможность распределения памяти дает нам применение функции calloc( ).

char *calloc( ); long *newmem;
newmem=(long *) calloc(100,sizeof(long));

Функция calloc( ) возвращает указатель на char. Нужно использовать оператор приведения типа, если вы хотите запомнить другой тип. calloc( ) имеет два аргумента, и оба они должны быть целыми без знака. Первый аргумент содержит количество требуемых ячеек памяти. Второй аргумент - размер каждой ячейки в байтах. Функция calloc( ) обнуляет содержимое всего блока. Ваша библиотека языка Си возможно представляет несколько других функций управления памятью, вы можете исследовать их самостоятельно!

Поиск

Яндекс.Метрика