|
| |
|
Тема 13. Стандартные библиотеки языка Си |
Система программированиz в Си содержит ряд предварительно определенных функций и макроопределений, находящихся в составе заголовочных файлов. Сами библиотеки не являются частью языка, а составляют системную среду поддерживающую стандарт Си.
В соответствии со стандартами ANSI должно быть 15 обязательных заголовочных файлов.
Таблица 1
Имя заголовочного файла | Назначение |
assert.h | Диагностика программы |
ctype.h | Преобразование и проверка типов |
errno.h | Проверка ошибок |
float.h | Функции для работы с типом с плавающей точкой |
limits.h | Предельные значения целых типов |
locale.h | Поддержка интернациональной среды (содержит прототипы функций, позволяющих модифицировать программы в зависимости от географического места ее выполнения) |
math.h | Математические функции |
setjmp.h | Возможности нелокальных переходов (содержит прототипы функций, которые позволяют обходить обычную последовательность вызова функции и возврата из нее) |
signal.h | Обработка сигналов |
stdarg.h | Поддержка функций с неопределенным числом параметров |
stddef.h | Разное (содержит объявления типов, используемых для некоторых вычислений) |
stdio.h | Библиотека стандартного ввода-вывода |
stdlib.h | Функции общего назначения (выделение памяти и т.д.) |
string.h | Функции для работы со строками |
time.h | Функции для работы с датами и временем |
13.1. Стандартная библиотека ввода-вывода. Работа с файлами |
В языке Си нет встроенных средств ввода-вывода. Все эти действия выполняются соответствующими функциями ввода-вывода.
Библиотека Си поддерживает три уровня ввода-вывода:
1. Ввод-вывод потока
2. Ввод-вывод нижнего уровня
3. Ввод-вывод для консоли и порта
13.1.1. Ввод-вывод потока |
При вводе-выводе потока все данные рассматриваются как поток отдельных байтов, не зависимо от того, какое используется устройство ввода-вывода, т.е. поддерживается некоторый абстрактный уровень между программой и физическим устройством. Эта абстракция и называется потоком.
Поток – это источник или получатель данных. Для пользователя поток- это либо файл на диске, либо физическое устройство.
Т.к. потоки не зависят от физических устройств, то одна и та же функция может записать информацию на диск или вывести ее на экран либо принтер.
Существует два типа потоков:
· текстовый
· бинарный
Текстовыйпоток – это последовательность строк, каждая из которых содержит 0 или более символов и заканчивается символами возврата каретки ’ \n’.
В текстовом потоке может не быть однозначного соответствия между символами, которые передаются в потоке и символами, которые выводятся на внешнее устройство. ОС может потребовать коррекции текстового потока (например, пара символов «возврат каретки – перевод строки» преобразуется в одиночный символ перевода строки на вводе, а комбинация клавиш Ctrl-z (0x1a) интерпретируется как символ конца потока на вводе)
Бинарныйпоток – это последовательность непреобразуемых байтов, которые взаимнооднозначно соответствуют тому, что выводится на внешнее устройство.
Поток связывается с физическим устройством или файлом путем его открытия. Как только файл открыт, то информация может передаваться между ним и программой. Эта связь разрывается путем закрытия потока. Открытие потока возвращает указатель на структуру типа FILE.
С началом выполнения программы автоматически открывается 5 потоков, которым соответствуют предопределенные указатели потоков:
1. stdin -стандартный ввод
2. stdout -стандартный вывод
3. stderr -стандартный вывод сообщений об ошибках
4. stdaux -стандартный дополнительный поток (COM1)
5. stdprn -стандартная печать (LPT1)
По умолчанию первые три (stdin, stdout и stderr) связаны с консолью пользователя и открываются в текстовом режиме. Это означает, что каждый раз, когда программа ожидает ввод со стандартного ввода, данные должны вводиться с консоли. Т.е. стандартный ввод – это ввод с клавиатуры, а стандартный вывод- это вывод на экран.
Назначения стандартному дополнительному потоку и стандартной печати зависят от конфигурации машины. Обычно stdaux связывается с дополнительным портом COM1, а stdprn – связывается с портом LPT1, к которому подключен принтер. Два последних потока открываются в двоичном режиме.
РЕКОМЕНДУЕТСЯ | Пользуйтесь преимуществами стандартных потоков ввода-вывода Си при написании своих программ. |
НЕ РЕКОМЕНДУЕТСЯ | Не переименовывайте и не заменяйте стандартные потоки без особой необходимости. Не пытайтесь воспользоваться потоком ввода stdin для целей вывода, например с помощью функции fprintf(). |
Режим доступа к файлам задается во время открытия файла как параметр функции открытия файла или специальной внешней переменной _fmode, описанной в заголовочных файлах «fcntl.h» или «stdlib.h» и может принимать 2 значения:
O_BINARY – двоичный режим;
- текстовый режим.
По умолчанию устанавливается знчение _fmode - O_TEXT.
13.2. Доступ к файлам через поток ввода-вывода |
Связующим звеном между файлом и потоком является указатель на файл, т.е. указатель на информацию, которая определяет различные характеристики файла (имя, статус, текущая позиция и т.д.).
Указатель файла – это указатель на структуру типа FILE, шаблон которой определен в «stdio.h», который используется для ссылки на поток.
Формат объявления указателя на файл:
FILE * имя_указателя_файла;
Например, FILE *fptr;
13.2.1. Открытие потока |
Функция fopen() открывает поток и связывает с ним файл с заданным именем. Она возвращает указатель, связанный с этим файлом или NULL, если попытка открытия неудачна (например, файл отсутствует).
Формат:
FILE*fopen (char* имя_файла, char* режим_открытия );
Параметр режим_открытия определяет режим открытияфайла и может принимать для текстовых файлов следующие значения:
“ r ” - файл открывается для чтения ( файл должен существовать );
“ w ” - файл создается для записи (старое содержимое удаляется);
“ a ” - файл открывается для добавления в конец существующего файла (файл создается, если он не существует);
“ r+ ” - файл открывается для исправления (чтения или записи) – файл должен существовать;
“ w+ ” - файл создается для чтения и записи (старое содержимое удаляется)
“ a+ ” - файл открывается или создается для исправления уже существующей информации и добавления новой в конец файла. Файл соэдается, если он не существует.
ПРИМЕЧАНИЕ | Если в любой из режимов добавить букву «b», то файл будет открыт в двоичном режиме. Например: “ rb ”, “ w+b ” и т.д. Если в любой из режимов добавить букву «t» или не добавлять вообще никакой буквы, то файл будет открыт в текстовом режиме (используется по умолчанию). Например: “ rt ”, “ a+t ”, “ w+ ”, “ a ” и т.д. |
Пример: простейшее открытие файла “dat.txt”
FILE *fp;
fp=fopen (“dat.txt”,”r”);
Пример: рекомендуется использовать следующий способ открытия файла
FILE *fp;
if ((fp=fopen (“dat.txt”,”r”))==NULL)
{
printf (“Невозможно открыть файл! Программа завершается!”);
exit (1);
}
else
...
ПРИМЕЧАНИЕ | Если не указать путь к файлу, то программа должна предполагать, что текущим каталогом является тот же, в котором находится и сама программа. Для указания пути к файлу программы следует добавить в нее соответствующий код. |
Функция freopen() переназначает указатель потока на другой поток.
Формат:
FILE*freopen (char* filename, char* mode, FILE *stream);
Данная функция открывает файл с указанным именем (filename) и режимом открытия (mode), и связывает его с потоком stream. Она возвращает stream или NULL (при неудаче). Обычно эта функция используется для замены файлов, связанных с stdin, stdout и stderr.
Пример: freopen (“file.dat”,”w”,stdout); - закрывает поток для стандартного вывода и переназначает stdout файлу file.dat.
Пример: fopen.c - использование функции fopen() для открытия файлов в разных режимах
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
FILE *fp;
char ch, filename[40], mode[4];
while (1)
{
printf("\nEnter a filename: ");
gets(filename);
printf("\nEnter a mode (max 3 characters): ");
gets(mode);
if ((fp = fopen(filename, mode))!= NULL)
{
printf("\nSuccessful opening %s in mode %s.\n",
filename, mode);
fclose(fp);
puts("Enter x to exit, any other to continue.");
if ((ch = getc(stdin)) == 'x')
break;
else
continue;
}
else
{
fprintf(stderr, "\nError opening file %s in mode %s.\n",
filename, mode);
puts("Enter x to exit, any other to try again.");
if ((ch = getc(stdin)) == 'x')
break;
else
continue;
}
}
return 0;
}
Результат:
Enter a file name: junk.txt
Enter a mode (max 3 characters): w
Successful opening junk.txt in mode w.
Enter x to exit, any other to continue.
J
Enter a file name: morejunk.txt
Enter a mode (max 3 characters): r
Error opening morejunk.txt in mode r.
Enter x to exit, any other to continue.
x
13.2.2. Закрытие потока |
Функция fclose() закрывает отдельный поток, а fcloseall() –закрывает все открытые потоки, за исключением стандартных.
Формат:
int fclose (FILE * fp );
int fcloseall ();
Эти две функции возвращают нуль – в случае успеха и EOF - в случае ошибки, где EOF (End Of File) – конец файла. При ошибке все данные из буфера считываются в файл. Если поток явно не закрывается, то он будет закрыт автоматически при выходе из программы.
ВНИМАНИЕ | Одновременно может быть открыто не более 20 потоков. |
Функция remove() уничтожает заданный файл.
Формат:
int remove (char * имя_файла );
Возвращает 0 в случае успешного удаления файла.
СОВЕТ | Рекомендуем, чтобы программа всегда спрашивала пользователя, действительно ли он хочет удалить файл. |
РЕКОМЕНДУЕТСЯ | Откройте файл, прежде чем пытаться читать из него данные или записывать их. Используйте операцию sizeof() при вызове функций fwrite() и fread(). Закрывайте все открытые файлы по окончанию работы с ними. |
НЕ РЕКОМЕНДУЕТСЯ | Не предполагайте, что операции с файлами заканчиваются успешно. Всегда проверяйте, как завершились операции открытия, чтения, записи файлов. Не злоупотребляйте функцией fcloseall(), если у вас нет причин закрывать сразу все потоки. |
Пример: remove.c - использование функции remove() для удаления файла с диска
#include <stdio.h>
int main(void)
{
char filename[80];
printf("Enter the filename to delete: ");
gets(filename);
if (remove(filename) == 0)
printf("The file %s has been deleted.\n", filename);
else
fprintf(stderr, "Error deleting the file %s.\n", filename);
return 0;
}
Результат:
Enter the filename to delete: *.bak
Error deleting the file *.bak
Результат:
Enter the filename to delete: remove.bak
The file remove.bak has been deleted.
13.3. Функции потокового ввода-вывода |
После открытия файла программа может выполнять файловый ввод-вывод.
Функции потокового ввода-вывода делятся на 4 группы:
Таблица 2
Функции, использующие стандартные потоки | Функции, требующие Указания имени потока | Назначение |
printf() | fprintf() | Форматированный вывод |
vprintf() | vfprintf() | Форматированный вывод с переменным списком параметров |
| ||
puts() | fputs() | Вывод строк |
putchar() | putc(), fputc() | Вывод символов |
scanf() | fscanf() | Форматированный вывод |
vscanf() | vfscanf() | Форматированный вывод с переменным списком параметров |
| ||
gets() | fgets() | Ввод строк |
getchar() | getc(), fgetc() | Ввод символов |
perror() |
| Ввод строк в stderr |
Пример: stream.c - простой пример работы со стандартными потоками
#include <stdio.h>
int main(void)
{
char buffer[256];
// ввод строки и немедленный ее вывод
puts(gets(buffer));
return 0;
}
13.3.1. Функции посимвольного ввода-вывода |
Функциипосимвольноговвода-вывода – это функции, за одно обращение к которым, переносится только один символ.
Функции посимвольного ввода:
· int fgetc (FILE * имя_указателя ); - возвращает символ из открытого файла, описываемого переменной типа FILE, на которую указывает указатель имя_указателя.
· int getc (FILE * имя_указателя ); -аналогична предыдущей функции, но является макроопределением.
· int fgetchar (void); - возвращает символ из файла стандартного ввода stdin.
· int getchar (void); - аналогична предыдущей функции, но является макроопределением.
· int ungetc (int символ, FILE * имя_указателя ); - возвращает символ (его ASCII-код) назад в поток, на который ссылается указатель имя_указателя. Следующая операция чтения из этого потока вернет тот же символ.
Функции посимвольного ввода в случае успеха возвращают прочитанный символ (его ASCII-код), Преобразованный в int а при ошибке – EOF.
РЕКОМЕНДУЕТСЯ | Уясните себе разницу между вводом с буферизацией и без нее. Помните, что при вводе символов некоторые функции отображают вводимые символы на экране, а некоторые – нет. |
НЕ РЕКОМЕНДУЕТСЯ | Не используйте функции не определенные в стандарте ANSI, если программа должна быть переносимой из одной среды в другую. Не ожидайте от нестандартных функций одинакового поведения в средах различных компиляторов. |
Пример: getchar1.c – использование функции getchar()
#include <stdio.h>
int main(void)
{
int ch;
while ((ch = getchar())!= '\n')
putchar(ch);
return 0;
}
Результат:
Напечатанный пользователем текст.
Напечатанный пользователем текст.
Пример: getchar2.c – ввод целых строк текста с помощью функции getchar()
#include <stdio.h>
#define MAX 80
int main(void)
{
char ch, buffer[MAX+1];
int x = 0;
while ((ch = getchar())!= '\n' && x < MAX)
buffer[x++] = ch;
buffer[x] = '\0';
printf("%s\n", buffer);
return 0;
}
Результат:
Это строка
Это строка
ПРИМЕЧАНИЕ | Существуют еще две функции getch() и getche(), не определенные стандартом ANSI. |
Функция getch(), которая получает следующий символ из потока stdin. Она вводит символ без буферизации и без дублирования его на экране. Она не определена в стандарте ANSI.
ВНИМАНИЕ | В приведенном ниже примере используется функция getch(), не определенная в стандарте ANSI. Соблюдайте осторожность при работе с такими функциями, поскольку не все компиляторы гарантируют их поддержку. Если при компиляции приведенной программы появляется сообщение об ошибке, то вероятная причина этого – отсутствие в нем поддержки функции getch(). Так, например, компиляторы от Symantec и Borlandее поддерживают, а от Microsoft – аналогичную функцию _getch() |
Пример: getch1.c - использование функции getch()
#include <stdio.h>
#include <conio.h>
int main(void)
{
int ch;
while ((ch = getch())!= '\n')
putchar(ch);
return 0;
}
Результат: Тестируем функцию getch()
Функция getche() практически ничем не отличается от getch(), с тем единственным отличием, что функция getche() выводит введенный символ в поток stdout.
ПРИМЕЧАНИЕ | Функция getche() не определенна стандартом ANSI, но многие компиляторы ее поддерживают. |
Для того чтобы прочитать текстовый файл можно использовать одну из следующих конструкций.
Пример1:
int ch;
FILE *fp;
ch=fgetc (fp);
while (ch!=EOF)
{
ch=fgetc (fp);
...
}
Пример2:
int ch;
FILE *fp;
while ((ch=fgetc(fp))!=EOF)
{
...
}
Функции посимвольного вывода:
Функции посимвольного вывода помещают символ (его ASCII-код) в открытый поток вывода. Символ преобразуется в char. В случае ошибки или достижения конца файла функции возвращают EOF, в случае успеха – выведенный символ.
· int fputc (int символ, FILE * имя_указателя ); - помещает символ в открытый файл, который описывается переменной типа FILE, на которую ссылается указатель имя_указателя.
· int putc (int символ, FILE * имя_указателя ); -аналогична предыдущей функции, но является макроопределением.
· int fputchar (int символ ); - помещает символ в открытый файл stdout.
· int putchar (int символ ); - аналогична предыдущей функции, но является макроопределением.
Пример: putchar1.c - демонстрация функции putchar()
#include <stdio.h>
int main(void)
{
int count;
for (count = 14; count < 128;)
putchar(count++);
return 0;
}
Пример: putchar2.c - отображение строки с помощью функции putchar()
#include <stdio.h>
#define MAXSTRING 80
char message[] = "Displayed with putchar().";
int main(void)
{
int count;
for (count = 0; count < MAXSTRING; count++)
{
if (message[count] == '\0')
{
putchar('\n');
break;
}
else
Дата добавления: 2015-08-29; просмотров: 22 | Нарушение авторских прав
<== предыдущая лекция | | | следующая лекция ==> |